안녕하세요 C++ 공부하고있는 대학생입니다.
이번에는 QT 이미지 합성하는것에 대해 정리해보려고 합니다.
우선 OpenCV를 통해 이미지를 불러오는 코드입니다.
(코드는 핵심만 적어두었습니다.)
QString filePath = QFileDialog::getOpenFileName(this, "Open Image File", QDir::currentPath());
QString fileName = filePath.section("/", -1);
string stdstring;
stdstring = filePath.toStdString();
firstImage = imread(stdstring, IMREAD_UNCHANGED);
if (firstImage.empty()) {
messagebox.setText("none image");
return;
}
imageCloneOrigin = firstImage.clone();
//namedWindow("OriginImage");
imshow("OriginImage", firstImage);
setMouseCallback("OriginImage", onMouseEventOrigin, (void*)& firstImage);
QFileDialog를 통해서 창을띄워서 이미지를 가져 올 수 있습니다. 위치는, 실행되는파일의 현재 디렉토리를 기준으로 잡았습니다.
이미지를 불러오는데에 있어 실패했을시, 예외처리로 firstImage.empty()를 통하여 해 주었습니다.
QT 의 string을 cv의 string으로 변환하기위해서
string stdstring;
stdstring = filePath.toStdString();
을 사용하였습니다.
다음은 합성하고자 하는 이미지를 불러와서 이미지를 합성까지하는 코드입니다.
QString filePath = QFileDialog::getOpenFileName(this, "Open Image File", QDir::currentPath());
QString fileName = filePath.section("/", -1);
string stdstring;
stdstring = filePath.toStdString();
secondImage = imread(stdstring, IMREAD_UNCHANGED);
if (firstImage.empty() && secondImage.empty()) {
messagebox.setText("none image");
return;
}
imshow("PaintImage", secondImage);
setMouseCallback("PaintImage", onMouseEventPaint, (void*)& secondImage);
cv::addWeighted(firstImage, 0.8, secondImage, 0.6, 0, secondImageRst);
imshow("result", secondImageRst);
setMouseCallback("result", onMouseEvent, (void*)& secondImageRst);
ROIImage = Mat::zeros(imageCloneOver.rows, imageCloneOver.cols, CV_8UC3);
imwrite("over.jpg", imageCloneOver);
이미지 합성하는 함수는 addWeighted 함수를 사용해서 이미지를 합성하였습니다.
setMouseCallback 함수는 이미지위에 페인팅(그림)을 하기위한 함수입니다.
다음은 ROI(관심영역) 에 대한 함수입니다.
for (int i = 0; i <secondImageRst.cols; i++) {
for (int j = 0; j < secondImageRst.rows; j++) {
if (imageCloneOver.at<Vec3b>(i, j)[0] != secondImageRst.at<Vec3b>(i, j)[0] &&
imageCloneOver.at<Vec3b>(i, j)[1] != secondImageRst.at<Vec3b>(i, j)[1] &&
imageCloneOver.at<Vec3b>(i, j)[2] != secondImageRst.at<Vec3b>(i, j)[2]) {
ROIImage.at<Vec3b>(i, j)[0] = secondImageRst.at<Vec3b>(i, j)[0];
ROIImage.at<Vec3b>(i, j)[1] = secondImageRst.at<Vec3b>(i, j)[1];
ROIImage.at<Vec3b>(i, j)[2] = secondImageRst.at<Vec3b>(i, j)[2];
}
}
관심영역을 표시해서 나중에 기존 합성된 이미지에 덧칠하기위한 수단으로 ROIImage 라는 매트릭스 클래스를 0배열로 모두 초기화시킨다음에, 합성한 이미지의 기존에 바뀐배열 (페인팅에의한 값의 변환) 의 부분을 가지고, 모두 0으로 초기화 된 ROIImage mat class에 해당되는 위치에 같은 색상으로 입힌 과정입니다.
결과를 간단히 보여드리면,
이렇게 합성이 되고,
이런식으로 색을 칠해주고 roi를 해주면,
이런식으로 저장이됩니다.
이걸 해보게 된 이유는 예전에 opencv를 조금 다루어본적이 있어서, 기억이 되새기면서 그림판을 사용하면서 재밌어 보여서 한번 만들어보게 되었습니다. 생각보다 많이 어려웠고, 그림판이 정말 대단한 프로그램이구나 를 깨닫게 되었습니다. roi경우는 그림판의 채우기 기능이있는데, 이것을 따라해보려고 한번 해 보았습니다. 이미지 합성의경우는 과연 내 프로그램에서도 합성된 이미지에서 채우기 기능이 되는지 한번 보려고 해 보았습니다.