MFC를 활용한 영상처리 프로그램
이미지의 색상 정보 및 여러 Data 를 검사하는 툴을 개발해 보았다. 기간은 6일 정도 소요됬던 것 같다.
기능에 대하여 간단히 설명하자면
1. ImageLoad Button : Inspect 하고자 하는 이미지를 불러온다. 단, 불러올 경우 레이블링 처리후 Align 을 잡게 하였다.
2. RGB or Gray Combo Box : 불러올 이미지를 32bit Color or 8bit Gray 에 대하여 전처리를 한다.
3. Set Divide Button : Check Box 의 경우 BOOL 역할을 하며 옆에 두 Edit에 원하는 X, Y Value 를 Set 한다. 단, Align 영역에 대해서만 진행을 해야한다. Divide 영역에 대한 Min Max Sigma 등을 차트에 나타낸다.
4. LineProfile Button : Button Click 하면 마우스로 이미지에 드래그를 할 수 있으며 드래그된 픽셀영역의 값을 2차원 그래프 x : Position, y = Intencity 로 나타낸다.
5. Data Transform : 차트의 값을 선택된 이미지 상태로 변경 후 검사하게 된다.
아래는 최종적인 프로그램 실행 인터페이스이다.

실행 프로그램 모습
개발 환경은 VisualStudio 2010 C++ 32bit MFC Interface 이며, NI Library, ChartViewer DLL 등을 사용하였다.
아래 그림을 보면 생성된 클래스는 많지가 않다.. Aurora 플랫폼으로 개발을 진행하지 않았다. (본인 회사에서 표준으로 사용하는 플랫폼이다. 공개 불가X) 그 이유는 개발 시작 당시는 LineProfile 만 제공하는 툴을 만들어 배포할 예정이였기 때문이다.. 그러다 계속 기능이 추가되었다.
더 이상 다양한 기능이 불필요했기 때문에 MVC 패턴 구조로 만들지 않았다.
간단한 Class 구조는 아래와 같다.

생성된 클래스
소스 중 Chart 에 Data 를 생성하는 함수이다.
for문에 있는 내용은 이미지 영역을 Divide 에 따라 참조 가능한 소스이다.
처음에는 switch case, if elssif 로 코딩하여 소스가 매우 방대해 졌지만 오랜생각 끝에
효율적인 코딩을 찾았다.. 맨 아래 for 문은 단순 data 취합이다.
void CD_ImageData::ImageUniformity(Image *pSrc, int nImageType, int nImageTrans)
{
int Imagewidth = 0, Imageheight = 0;
imaqGetImageSize(pSrc, &Imagewidth, &Imageheight);
if((Imagewidth <= 0) || (Imageheight <= 0)) return;
Image *pTmp = imaqCreateImage(IMAQ_IMAGE_U8, 4);
if(nImageType == 1)
{
if(nImageTrans >= 0)
{
imaqDuplicate(pTmp, pSrc);
}
else
{
imaqExtractColorPlanes(pSrc, IMAQ_RGB, NULL, pTmp, NULL); // 여기서 한번에 나누면 될듯
}
}
else if(nImageType == 0)
{
imaqDuplicate(pTmp, pSrc);
}
else
{
return;
}
if((nDivide_X * nDivide_Y) > (Imagewidth * Imageheight) / 10)
{
nDivide_X = sqrt((Imagewidth * Imageheight) / 10.f);
nDivide_X = sqrt((Imagewidth * Imageheight) / 10.f);
}
vecROIs.push_back(CRect(0, 0, Imagewidth, Imageheight));
int pieceX = Imagewidth / nDivide_X;
int pieceY = Imageheight / nDivide_Y;
for(int y = 0; y < nDivide_Y; ++y)
{
for(int x = 0; x < nDivide_X; ++x)
{
int l = pieceX * x;
int t = pieceY * y;
int r = l + pieceX;
int b = t + pieceY;
vecROIs.push_back(CRect(l, t, r, b));
}
}
for(size_t i = 0; i < vecROIs.size(); ++i)
{
Rect rect = imaqMakeRect(vecROIs[i].top, vecROIs[i].left, vecROIs[i].Height(), vecROIs[i].Width());
Image *roi_image = imaqCreateImage(IMAQ_IMAGE_U8, 4);
imaqSetImageSize(roi_image, rect.width, rect.height);
imaqCopyRect(roi_image, pTmp, rect, imaqMakePoint(0, 0));
QuantifyReport *report = imaqQuantify(roi_image, NULL);
double dMaxvalue = report->global.max;
double dMinvalue = report->global.min;
double dAvg = report->global.mean;
double dUniformity = (dMaxvalue - dMinvalue) / (2 * dAvg) * 100;
double dRange = dMaxvalue - dMinvalue;
double dSigma = report->global.stdDev;
UNIFORMITY_INFO strData;
strData.strNameNumber.Format(_T("%d") , i);
strData.strMax.Format(_T("%f") , dMaxvalue);
strData.strMin.Format(_T("%f") , dMinvalue);
strData.strRange.Format(_T("%f") , dRange);
strData.strAverage.Format(_T("%f") , dAvg);
strData.strUniformity.Format(_T("%f") , dUniformity);
strData.strSigma.Format(_T("%f") , dSigma);
m_vecData.push_back(strData);
imaqDispose(report);
imaqDispose(roi_image);
}
imaqDispose(pTmp);
}
소스를 너무 오랜만에 열어서 보면 내가 한게 맞나 라는 생각이 너무 든다... 블로그를 개설하고 처음으로 게시물을 작성해 보는거라 다소 매끄럽지 않을 수도 있지만 점차 나아지길 바라며 오늘은 여기까지 마치겠다.