mfc-imageProcessing 이미지 팽창, 침식기능을 추가하자
2018, May 30
픽셀 단위 작업
- 밝기 조절
- 콘트라스트 조절
- 흑백이미지를 바이너리화
영역 단위 작업
- 이진 이미지 침식
- 이진 이미지 팽창
이전까지 픽셀단위 이미지를 조작하는 작업을 했다.
이번 포스트에서는 영역단위 이미지를 조작하는 작업을 해보자.
이진 이미지 침식이란 바이너리 이미지를 주변 x 픽셀만큼 보고 검은색이 있다면 검게 만드는 작업이다. 이진 이미지 팽창이란 바이너리 이미지를 주변 x 픽셀만큼 보고 하얀색이 있다면 하얗게 만드는 작업이다.
주로 이미지의 노이즈를 줄일 때 사용한다.
이진 이미지 침식
ImageProc.h
class ImageProc
{
...
public :
static void BinaryErosion(unsigned char* image_gray,
const int width, const int height, unsigned char ksize);
}
ImageProc.cpp
// 현재 픽셀이 검은색이면 건너뛴다.
// 주변 x 픽셀만큼 보고 검은색이 있다면 검게 만든다.
void ImageProc::BinaryErosion(unsigned char* image_gray,
const int width, const int height, unsigned char ksize)
{
// ksize 는 홀수로 받아서 양옆 neighbor 만큼 본다.
unsigned char neighbor = ksize /2 ;
// 침식이미지를 저장할 버퍼를 생성한다.
unsigned char* temp = new unsigned char[width*height];
memcpy(temp, image_gray, sizeof(unsigned char)*width*height);
for(int j=0; j<height; j++)
{
for(int i=0; i<width; i++)
{
//현재 픽셀이 검은색이면 건너뛴다.
if(image_gray[width*j + i] == 0)
{
temp[width*j + i] =0;
continue;
}
// 주변 픽셀이 검은색인지 확인
bool bBlack = false;
for( int l = j-neighbor; l< j+1+neighbor; l++)
{
for (int k = i-neighbor; k<i+1+neighbor; k++)
{
if(image_gray[width*l + k] == 0)
{
temp[width*j + i]= 0;
bBlack = true;
break;
}
}
if(bBlack)
break;
}
}
}
memcpy(image_gray, temp, sizeof(unsigned char)*width*height);
delete[] temp;
}
이벤트를 추가한다.
ImageProcessingDoc.h
class ImageProcessingDoc : public CDocument
{
...
public:
afx_msg void OnAreaprocessingBinaryerosion();
}
ImageProcessingDoc.cpp
void CImageProcessingDoc::OnAreaprocessingBinaryerosion()
{
// 먼저 binarization 한다.
ImageProc::Binarization(m_Images[cur_index].image_gray,
m_Images[cur_index].width, m_Images[cur_index].height, 127);
// 주변 1개의 픽셀을 바라본다.
ImageProc::BinaryErosion(m_Images[cur_index].image_gray,
m_Images[cur_index].width, m_Images[cur_index].height, 3);
CImageProcessingView* pView = (CImageProcessingView*)((CMainFrame*)(AfxGetApp()->m_pMainWnd))->GetActiveView();
pView->SetDrawImage(m_Images[cur_index].image_color, m_Images[cur_index].image_gray,
m_Images[cur_index].width, m_Images[cur_index].height);
pView->OnInitialUpdate();
}
실행하면 다음 그림과 같이 보인다.
이진 이미지 팽창
ImageProc.h
class ImageProc
{
...
public :
static void BinaryDilation(unsigned char* image_gray,
const int width, const int height, unsigned char ksize);
}
ImageProc.cpp
// 현재 픽셀이 하얀색이면 건너뛴다.
// 주변 x 픽셀만큼 보고 하얀색이 있다면 하얗게 만든다.
void ImageProc::BinaryDilation(unsigned char* image_gray,
const int width, const int height, unsigned char ksize)
{
// ksize 는 홀수로 받아서 양옆 neighbor 만큼 본다.
unsigned char neighbor = ksize /2 ;
// 팽창이미지를 저장할 버퍼를 생성한다.
unsigned char* temp = new unsigned char[width*height];
memcpy(temp, image_gray, sizeof(unsigned char)*width*height);
for(int j=0; j<height; j++)
{
for(int i=0; i<width; i++)
{
//현재 픽셀이 하얀색이면 건너뛴다.
if(image_gray[width*j + i] == 0)
{
temp[width*j + i] =0;
continue;
}
// 주변 픽셀이 하얀색인지 확인
bool bWhite = false;
for( int l = j-neighbor; l< j+1+neighbor; l++)
{
for (int k = i-neighbor; k<i+1+neighbor; k++)
{
if(image_gray[width*l + k] == 0)
{
temp[width*j + i]= 0;
bWhite = true;
break;
}
}
if(bWhite)
break;
}
}
}
memcpy(image_gray, temp, sizeof(unsigned char)*width*height);
delete[] temp;
}
이벤트를 추가한다.
ImageProcessingDoc.h
class ImageProcessingDoc : public CDocument
{
...
public:
afx_msg void OnAreaprocessingBinarydilation();
}
ImageProcessingDoc.cpp
void CImageProcessingDoc::OnAreaprocessingBinarydilation()
{
// 먼저 binarization 한다.
ImageProc::Binarization(m_Images[cur_index].image_gray,
m_Images[cur_index].width, m_Images[cur_index].height, 127);
// 주변 1개의 픽셀을 바라본다.
ImageProc::BinaryDilation(m_Images[cur_index].image_gray,
m_Images[cur_index].width, m_Images[cur_index].height, 3);
CImageProcessingView* pView = (CImageProcessingView*)((CMainFrame*)(AfxGetApp()->m_pMainWnd))->GetActiveView();
pView->SetDrawImage(m_Images[cur_index].image_color, m_Images[cur_index].image_gray,
m_Images[cur_index].width, m_Images[cur_index].height);
pView->OnInitialUpdate();
}
실행하면 아래와 같이 보인다