본문 바로가기
대한상공회의소 스마트팩토리 교육/데이터베이스

[데이터베이스 운영] DBMS 기초 «수업-8» : 이미지 파일(RAW) 데이터베이스(DB)에 저장 방법

by 나는영하 2022. 5. 3.

※ 주의사항 

본 블로그는 수업 내용을 바탕으로 제가 이해한 부분을 정리한 블로그입니다.
본 내용을 참고로만 보시고, 틀린 부분이 있다면 지적 부탁드립니다!

감사합니다😁

 


이미지 파일(RAW) 데이터베이스에 저장

LAST_INSERT_ID()

AUTO_INCREMENT


안녕하세요!!

오늘부터는 그 동안 배운 데이터베이스(DB) 지식을 바탕으로

지난 미니프로젝트(이미지영상처리 프로그램)에 적용시켜보도록 하겠습니다.

 

빨간색 부분이 오늘 처리할 과정에 해당

지난 수십시간에 걸쳐서 만든 영상처리 프로그램의 구성도입니다. 지난 제 글들을 본적이 있다면 위와 같은 구성도는 눈에 띌거라 생각이 됩니다. 하지만 지난 구성도와는 다른부분이 있다면 이미지 파일을 바로 2차원(COLOR는 3차원이겠죠?) 배열에 넣는것이 아니라 이미지 파일을 데이터베이스에 저장한 다음 데이터베이스에 저장되어 있는 픽셀(화소점)값을 가지고 이미지 영상처리를 수행하도록 할 예정입니다. 

 

오늘은 그 첫번째 스텝으로 회색조(GrayScale) 이미지 파일을 데이터베이스에 저장하는 과정을 알아보겠습니다.(구성도로 따지면 빨간색 네모박스로 처리되어 있는 부분이 오늘 할 부분입니다!!)

 

제일먼저 MySQL에서 이미지 파일에 대한 정보를 저장하기 위한 데이터베이스와 테이블을 생성 하고, 

C#에서 생성한 테이블에 이미지 파일에 대한 정보와 화소점 값을 저장하도록 하겠습니다.

 

## Main Form 코드 ##

Form1.cs
0.01MB

 


 

1. 데이터베이스 및 테이블 생성(Using My SQL)

Image Database 와 Image, Pixel Table 구조

위의 그림을 기준으로 Jisoo라는 파일은 PRIMARY KEY 값 "2"를 가지고 Image_Table에 이미지 파일 관련된 정보를 저장하고 있습니다. 또한 Pixel_Table은 Image_Table에대해 종속관계로서 같은 파일 번호 열을 외래키(FOREIGN KEY)로 가지고 있습니다.(외래키라고해서 꼭 기본키와 열이름이 같을 필요는 없지만 일반적으로 동일하게 하는게 좋습니다 ^^;)

 

Pixel_Table 에서는 Jisoo라는 이미지파일의 화소점 값과 해당 값의 위치정보(x,y좌표)를 저장하고 있는데 이는 파일번호(f_id)열을 통해 이미지 파일이 많더라도 서로 구분지어서 정보를 저장할 수 있습니다. 


1-1. Image 데이터베이스와 Image, Pixel 테이블 (PK와 FK)

먼저 이미지 파일에 관련된 정보 및 화소점 값을 저장하기 위한 데이터베이스와 테이블을 생성해야합니다.

테이블을 생성하기 위해선 제약 조건을 알아야 하며, 데이터 무결성을 위한 제약 조건에는 PRIMARY KEY(기본키), FOREIGN KEY(외래키), UNIQUE, CHECK, DEFAULT 정의, NULL값 허용이 있습니다. 이에 관련된 자세한 내용은 별도로 서칭을 통해 알아보도록 하고, 지금은 이러한 제약조건을 활용해서 Image와 Pixel 테이블을 생성해보겠습니다.

 

테이블에 대한 설명(속성)

위처럼 raw_pixel 테이블은 raw_image테이블에 종속된 테이블로서 기본키 테이블과 외래키 테이블은 1 : 多의 관계를 띄고 있습니다. (PRIMARY KEY 값(一) :  FOREIGN KEY 값(多)) 

※ KEY에서 MUL은 Multiple을 뜻하며 내부적으로 저장되는 값의 상태에 따라 인덱스를 할당하여 검색속도를 빠르게 처리하기 위한 키로서 일반적으로 외래키(FOREIGN KEY)라고 합니다. 

 

확장자명은 DEFAULT 값으로 "RAW" 확장자를 입력하도록 되어있지만 이는 GRAYSACLE 이미지에 한해서 설정한 부분이고 나중에 되면 변경될 예정입니다. 

 

또 특이한 점은 raw_image 테이블의 f_id 열의 AUTO_INCREMENT라는 속성입니다. 이는 별도로 사용자가 데이터를 입력하지 않고 INSERT를 통해 데이터를 입력하면 자동으로 1씩 순차적으로 값이 입력되는 명령어 입니다. 

 

✔ 나중에 기본키(PRIMARY KEY)의 마지막 입력 값을 반환하는 명령어(LAST_INSERT_ID())를 사용하게 되는데 AUTO_INCREMENT를 통해 최종적으로 입력된 값을 외래키 테이블의 외래키열에 반환하게 됩니다. 자세한 내용은 "2-3. Pixel Table 데이터 입력(화소값 관련 정보 저장)"에서 설명하겠습니다. 

 


1-2. 쿼리문

DROP DATABASE raw_db;
CREATE DATABASE raw_db;
USE raw_db;
CREATE TABLE raw_image(
	        f_id INT AUTO_INCREMENT NOT NULL PRIMARY KEY, -- 파일 번호 // 자동증가 // 기본키
	        fname VARCHAR(256) NOT NULL,  -- 파일 명 
	        extname VARCHAR(10) NOT NULL DEFAULT 'RAW',  -- 확장자 명
	        fsize BIGINT NOT NULL, -- INT 보다 큰 타입
	        f_width SMALLINT NOT NULL, -- 이미지 폭
	        f_height SMALLINT NOT NULL -- 이미지 높이
	-- 이미지가 원본인지, 영상처리된 결과이지, 또 어떠한 효과를 준건지...?
	-- 업로드 사용자, 업로드 날짜, 업로드 장비, 이미지 생성 일자, 이미지 생성 장소 등등
);
 CREATE TABLE raw_pixel(
			f_id INT NOT NULL, -- 파일 아이디 (FK) 
			p_x SMALLINT NOT NULL, -- X위치 
			p_y SMALLINT NOT NULL, -- Y위치 
			p_value TINYINT UNSIGNED NOT NULL, -- 픽셀값
			FOREIGN KEY (f_id) REFERENCES raw_image(f_id) -- f_id를 외래키로 지정
		);	
SELECT * FROM raw_image;	
SELECT * FROM raw_pixel;

- PRIMARY KEY(기본키) : raw_image 테이블의 f_id열

- FOREIGN KEY(외래키) : raw_pixel 테이블의 f_id열

 

위의 테이블에 대한 열은 간단한 예제를 위해 기본적인 정보만 저장한 것으로써 추후 더 추가될 예정입니다. 특히 칼라 이미지를 사용할경우 화소점값은 R,G,B 값을 따로 저장해야 할 것이며, 이미지 처리를 하고 난 후의 화소점 값을 저장하는 열도 필요할 것이라 생각 됩니다(지금은 당장 기본 RAW 파일을 DB에 저장하는 과정에 집중해서 생각해보겠습니다.) 

 


2. 이미지파일(RAW) 데이터베이스에 저장(Using C#) 

2-1. Form 구성 

Main Form

① tb_fullname : TextBox / 파일의 이름을 포함한 경로를 불러오고 입력하는 부분

② btn_upload : Button / 클릭 시 tb_fullname에 있는 파일을 프로그래밍 과정을 통해 가공하여 해당 파일의 정보 및 화소값 등 디지털 이미지 처리에 필요한 데이터를 DB의 Table에 저장하는 부분

③ btn_image_select : Button / 클릭 시 OpenFileDiaglog를 띄우며 이미지 파일을 찾아서 tb_fullname에 경로를 포함한 파일명을 띄우는 부분  

④ 위의 구성을 제외한 이벤트부 : 기존의 DB 연동 프로그래밍과 동일한 부분으로 Main Form Load 이벤트와 Main Form Closed 이벤트로 구성되어 있습니다. Load 이벤트는 전역변수 값을 기준으로 DB에 연결을 해주며 Closed 이벤트는 DB와의 연결을 끊도록 프로그래밍 되어 있습니다. 

 

자세한 내용은 지난 글을 참고하도록 합시다!

2022.04.28 - [데이터베이스] - [데이터베이스 운영] DBMS 기초 «수업-6» : 데이터베이스(DB) 연동 프로그래밍 기초 Using C# - ② : GUI 환경 기초

 

[데이터베이스 운영] DBMS 기초 «수업-6» : 데이터베이스(DB) 연동 프로그래밍 기초 Using C# - ② : GUI

※ 주의사항 ※ 본 블로그는 수업 내용을 바탕으로 제가 이해한 부분을 정리한 블로그입니다. 본 내용을 참고로만 보시고, 틀린 부분이 있다면 지적 부탁드립니다! 감사합니다😁 데이터베이스

920416.tistory.com

 


2-2. Image Table 데이터 입력(이미지 관련 정보 저장)

/*
CREATE TABLE raw_image(
    f_id INT AUTO_INCREMENT NOT NULL PRIMARY KEY,
    fname VARCHAR(256) NOT NULL,  -- 파일 명 
    extname VARCHAR(10) NOT NULL DEFAULT 'RAW',  -- 확장자 명
    fsize BIGINT NOT NULL, -- INT 보다 큰 타입
    f_width SMALLINT NOT NULL,
    f_height SMALLINT NOT NULL
    -- 이미지가 원본인지, 영상처리된 결과이지, 또 어떠한 효과를 준건지...?
    -- 업로드 사용자, 업로드 날짜, 업로드 장비, 이미지 생성 일자, 이미지 생성 장소 등등
);      
 */
 
// raw_image 테이블을 채우기위한 코드부. fullname을 가지고 구한다.
String fullname = tb_fullname.Text;
// '\'를 기준으로 문자열을 그룹으로 나눈다. 
//   C:\images\GrayScale\RAW\LENNA512.RAW
// 즉 위와 같은 경로일경우 tmp[0] : c: / tmp[1] : iamges / tmp[2] : GrayScale
String[] tmp = fullname.Split('\\'); 
String filename = tmp[tmp.Length - 1]; // tmp[] 배열의 마지막 즉, LENNA512.RAW 
tmp = filename.Split('.'); // LENNA512.RAW를 '.' 기준으로 나누기
String fname = tmp[0];
String extname = tmp[1];
long fsize = new FileInfo(fullname).Length;
int f_height; int f_width;
f_height = f_width = (int)Math.Sqrt(fsize);

// 쿼리문 입력
sql = "INSERT INTO raw_image(fname, extname, fsize, f_width, f_height) VALUES('" + fname;
sql += "', '" + extname + "', " + fsize + ", " + f_width + ", " + f_height + ")";

cmd.CommandText = sql;
cmd.ExecuteNonQuery();

✔ String.Split 메서드 : 지정된 구분 문자에 따라 문자열을 부분 문자열로 분할합니다.

즉, 위에서는 두번 사용하는데 처음에는 '\'기호를 기준으로 문자열을 분할해서 파일의 경로에서 파일의 이름과 확장자만을 추출하였으며

두번째는 '.'을 기준으로 파일의 이름과 확장자를 각각 분리하였습니다. 

 

✔ INSERT 문에서 PRIMARY KEY 값 입력 제외 (실제로는 자동 입력)

INSERT Quarry문에서 중복되어서도, NULL값이 있어서도 안되는 PRIMARY KEY의 값을 입력하지 않는데 그 이유는 raw_image 테이블을 생성할때 PRIMARY KEY열인 f_id열을 AUTO_INCREMENT로 설정하여서 해당 테이블에 한행이 INSERT 될때마다 자동으로 PRIMARY KEY값을 +1씩 올려서 자동으로 입력되게 됩니다.

 

따라서 INSERT문에서 f_id열의 값을 누락하여도 상관이 없게 됩니다. 

 


2-3. Pixel Table 데이터 입력(화소값 관련 정보 저장)

/*
CREATE TABLE raw_pixel(
    f_id INT NOT NULL, -- 파일 아이디 (FK) // NOT NULL을 하면 오류 발생 
    p_x SMALLINT NOT NULL, -- X위치 
    p_y SMALLINT NOT NULL, -- Y위치 
    p_value TINYINT UNSIGNED NOT NULL, -- 픽셀값
    FOREIGN KEY (f_id) REFERENCES raw_image(f_id)
);
 */
// raw_pixel 테이블을  채우기 위한 코드부, 이중for문 사용 
int p_x, p_y, p_value;
 BinaryReader br = new BinaryReader(File.Open(fullname, FileMode.Open)); //  
 for(int i = 0; i < f_height; i++)
 {
     for(int k = 0; k < f_width; k++)
     {
         p_x = i;
         p_y = k;
         p_value = (int)br.ReadByte();
         sql = "INSERT INTO raw_pixel(f_id,p_x,p_y,p_value) VALUES(";
         sql += "LAST_INSERT_ID()," + p_x + "," + p_y + "," + p_value + ")";

         cmd.CommandText = sql;
         cmd.ExecuteNonQuery();
     }
 }
 br.Close();
tb_fullname.Text = "";

✔ BinaryReader.ReadBytes 메서드를 통해 해당 파일의 화소점 값(바이트 단위의 2진 데이터값)을 받아서 p_value열에 저장하게 됩니다. 

 

✔ PRIMARY KEY(f_id_)값을 가져오는 방법

raw_piexel 테이블에 f_id(외래키)열의 값을 저장하기 위해서는 raw_image 테이블의 기본키인 f_id의 값을 불러와야합니다. 그러기 위해서 제가 발견한 방법으로는 크게 3가지가 있습니다. (실제론 다양한 방법이 있겠지만 저는 3가지를 확인했습니다. 😥) 

 

① SELECT 문을 통해서 f_id열을 오름차순 정렬 후 마지막 데이터 값을 불러오기

sql = "SELECT * FROM raw_image ORDER BY f_id DESC LIMIT 1";

ORDER BY 명령어를 통해 f_id를 오름차순으로 정렬하고, DESC LIMIT 1이란 명령어로 해당 열의 마지막값에서 1개만을 선택해 반환해줍니다. 

 

② SELECT 문에서 LAST_INSERT_ID 명령어를 통해 마지막 PK키를 받아서 넣기

sql = "SELECT LAST_INSERT_ID()";
cmd.CommandText = sql;
MySqlDataReader reader;
int f_id = Convert.ToInt32(cmd.ExecuteScalar());

SqlCommand.ExecuteScalar 메서드 : 쿼리를 실행하고 쿼리에서 반환한 결과 집합에서 첫번째 행의 첫번째 열을 반환합니다. 추가 열이나 행은 무시됩니다.

즉, LAST_INSERT_ID 명령어를 통해 마지막 행의 기본키값을 반환하고 이를 변수에 저장하는 형태입니다. 

 

③ INSERT 문에서 바로 LAST_INSERT_ID 명령어를 통해 마지막 PK키 값을 받아서 넣기 

sql = "INSERT INTO raw_pixel(f_id,p_x,p_y,p_value) VALUES(";
sql += f_id +"," + p_x + "," + p_y + "," + p_value + ")";

2번형태와 비슷하지만 INSERT문의 VALUES절에서 바로 해당 명령어를 사용해서 마지막 PRIMARY KEY값을 반환받는 형태입니다. 

 

저는 제일 간단하면서 편한 3번 방법을 사용해서 프로그래밍을 하였습니다.

댓글