문제
풀이 코드
#include<iostream>
#include<vector>
#include"opencv2/core/core.hpp"
#include"opencv2/highgui/highgui.hpp"
#include"opencv2/imgproc/imgproc.hpp"
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
#include <stdio.h>
void CvColorModels(Mat bgr_img) {
Mat gray_img, rgb_img, hsv_img, yuv_img, xyz_img;
cvtColor(bgr_img, gray_img, COLOR_BGR2GRAY);
cvtColor(bgr_img, rgb_img, COLOR_BGR2RGB);
cvtColor(bgr_img, hsv_img, COLOR_BGR2HSV);
cvtColor(bgr_img, yuv_img, COLOR_BGR2YCrCb);
cvtColor(bgr_img, xyz_img, COLOR_BGR2XYZ);
// Gray 이미지를 BGR로 변환하여 채널을 맞춥니다.
cvtColor(gray_img, gray_img, COLOR_GRAY2BGR);
// 첫 번째 행의 이미지들을 합칩니다.
Mat first_row;
vector<Mat> imgs_1 = { bgr_img, gray_img, rgb_img };
hconcat(imgs_1, first_row);
// 두 번째 행의 이미지들을 합칩니다.
Mat second_row;
vector<Mat> imgs_2 = { hsv_img, yuv_img, xyz_img };
hconcat(imgs_2, second_row);
// 첫 번째 행을 디스플레이합니다.
imshow("First Row", first_row);
waitKey(0);
// 두 번째 행을 디스플레이합니다.
imshow("Second Row", second_row);
waitKey(0);
// 첫 번째 행과 두 번째 행을 수직으로 합칩니다.
Mat combined;
vconcat(first_row, second_row, combined);
// 최종 결과를 디스플레이합니다.
imshow("Combined Results", combined);
waitKey(0);
// 최종 결과를 이미지 파일로 저장합니다.
imwrite("CvColorModels.png", combined);
}
Mat GetYCbCr(Mat src_img) {
double b, g, r, y, cb, cr;
Mat dst_img;
src_img.copyTo(dst_img);
//화소 인덱싱
for (int row = 0; row < dst_img.rows; row++) {
for (int col = 0; col < dst_img.cols; col++) {
//BGR취득
//openCV의 Mat은 BGR의 순서를 가짐에 유의
b = (double)dst_img.at<Vec3b>(row, col)[0];
g = (double)dst_img.at<Vec3b>(row, col)[1];
r = (double)dst_img.at<Vec3b>(row, col)[2];
//색상 변환 계산
//정확한 계산을 위해 double 자료형 사용
y = 0.2627 * r + 0.678 * g + 0.0593 * b;
cb = -0.13963 * r - 0.36037 * g + 0.5 * b;
cr = 0.5 * r - 0.45979 * g - 0.04021 * b;
//오버플로우 방지
y > 255.0 ? 255.0 : y < 0 ? 0 : y;
cb > 255.0 ? 255.0 : cb < 0 ? 0 : cb;
cr > 255.0 ? 255.0 : cr < 0 ? 0 : cr;
//변환된 색상 대입
//double 자료형의 값을 본래 자료형으로 반환
dst_img.at<Vec3b>(row, col)[0] = (uchar)y;
dst_img.at<Vec3b>(row, col)[1] = (uchar)cb;
dst_img.at<Vec3b>(row, col)[2] = (uchar)cr;
}
}
imshow("results", dst_img);
waitKey(0);
return dst_img;
}
Mat CvKmeans(Mat src_img, int k) {
//2차원 영상 -> 1차원 벡터
Mat samples(src_img.rows * src_img.cols, src_img.channels(), CV_32F);
for (int y = 0; y < src_img.rows; y++) {
for (int x = 0; x < src_img.cols; x++) {
if (src_img.channels() == 3) {
for (int z = 0; z < src_img.channels(); z++) {
samples.at<float>(y + x * src_img.rows, z) = (float)src_img.at<Vec3b>(y, x)[z];
}
}
else {
samples.at<float>(y + x + src_img.rows) = (float)src_img.at<uchar>(y, x);
}
}
}
//opencv k-means 수행
Mat labels;
Mat centers;
int attemps = 5;
kmeans(samples, k, labels,
TermCriteria(TermCriteria::MAX_ITER | TermCriteria::EPS, 10000, 0.0001),
attemps, KMEANS_PP_CENTERS, centers);
//1차원 벡터 => 2차원 영상
Mat dst_img(src_img.size(), src_img.type());
for (int y = 0; y < src_img.rows; y++) {
for (int x = 0; x < src_img.cols; x++) {
int cluster_idx = labels.at<int>(y + x * src_img.rows, 0);
if (src_img.channels() == 3) {
for (int z = 0; z < src_img.channels(); z++) {
dst_img.at<Vec3b>(y, x)[z] =
(uchar)centers.at<float>(cluster_idx, z);
//군집판별 결과에 따라 각 군집의 중앙값으로 결과 생성
}
}
else {
dst_img.at<uchar>(y, x) = (uchar)centers.at<float>(cluster_idx, 0);
}
}
}
imshow("results", dst_img);
waitKey(0);
return dst_img;
}
void createClustersInfo(Mat imgInput, int n_cluster, vector<Scalar>& clustersCenters,
vector<vector<Point>>& ptInClusters) {
RNG random(cv::getTickCount());
for (int k = 0; k < n_cluster; k++) {
Point centerKPoint;
centerKPoint.x = random.uniform(0, imgInput.cols);
centerKPoint.y = random.uniform(0, imgInput.rows);
Scalar centerPixel = imgInput.at<Vec3b>(centerKPoint.y, centerKPoint.x);
Scalar centerK(centerPixel.val[0], centerPixel.val[1], centerPixel.val[2]);
clustersCenters.push_back(centerK);
vector<Point>ptInClustersK;
ptInClusters.push_back(ptInClustersK);
}
}
double computeColorDistance(Scalar pixel, Scalar clusterPixel) {
double diffBlue = pixel.val[0] - clusterPixel[0];
double diffGreen = pixel.val[1] - clusterPixel[1];
double diffRed = pixel.val[2] - clusterPixel[2];
double distance = sqrt(pow(diffBlue, 2) + pow(diffGreen, 2) + pow(diffRed, 2));
return distance;
}
void findAssociatedCluster(Mat imgInput, int n_cluster, vector<Scalar> clustersCenters,
vector<vector<Point>>& ptInClusters) {
for (int r = 0; r < imgInput.rows; r++) {
for (int c = 0; c < imgInput.cols; c++) {
double minDistance = INFINITY;
int closestClusterIndex = 0;
Scalar pixel = imgInput.at<Vec3b>(r, c);
for (int k = 0; k < n_cluster; k++) {
Scalar clusterPixel = clustersCenters[k];
double distance = computeColorDistance(pixel, clusterPixel);
if (distance < minDistance) {
minDistance = distance;
closestClusterIndex = k;
}
}
ptInClusters[closestClusterIndex].push_back(Point(c, r));
}
}
}
double adjustClusterCenters(Mat src_img, int n_cluster, vector<Scalar>& clustersCenters,
vector<vector<Point>>ptInClusters, double& oldCenter, double newCenter) {
double diffChange;
for (int k = 0; k < n_cluster; k++) {
vector<Point>ptInCluster = ptInClusters[k];
double newBlue = 0;
double newGreen = 0;
double newRed = 0;
if (ptInCluster.size() > 0) { // 포인트가 있을 때만 계산
for (int i = 0; i < ptInCluster.size(); i++) {
Scalar pixel = src_img.at<Vec3b>(ptInCluster[i].y, ptInCluster[i].x);
newBlue += pixel.val[0];
newGreen += pixel.val[1];
newRed += pixel.val[2];
}
newBlue /= ptInCluster.size();
newGreen /= ptInCluster.size();
newRed /= ptInCluster.size();
}
else {
continue; // 포인트가 없는 클러스터는 건너뜁니다
}
Scalar newPixel(newBlue, newGreen, newRed);
newCenter += computeColorDistance(newPixel, clustersCenters[k]);
clustersCenters[k] = newPixel;
}
newCenter /= n_cluster;
diffChange = abs(oldCenter - newCenter);
oldCenter = newCenter;
return diffChange;
}
Mat applyFinalClusterTolmage(Mat src_img, int n_cluster, vector<vector<Point>>ptInClusters,
vector<Scalar>clustersCenters) {
Mat dst_img(src_img.size(), src_img.type());
for (int k = 0; k < n_cluster; k++) {
vector<Point>ptInCluster = ptInClusters[k];
for (int j = 0; j < ptInCluster.size(); j++) {
dst_img.at<Vec3b>(ptInCluster[j])[0] = clustersCenters[k].val[0];
dst_img.at<Vec3b>(ptInCluster[j])[1] = clustersCenters[k].val[1];
dst_img.at<Vec3b>(ptInCluster[j])[2] = clustersCenters[k].val[2];
}
}
return dst_img;
}
Mat MyKmeans(Mat src_img, int n_cluster) {
vector<Scalar>clustersCenters;
vector<vector<Point>>ptInClusters;
double threshold = 0.001;
double oldCenter = INFINITY;
double newCenter = 0;
double diffChange = oldCenter - newCenter;
createClustersInfo(src_img, n_cluster, clustersCenters, ptInClusters);
while (diffChange > threshold) {
newCenter = 0;
for (int k = 0; k < n_cluster; k++) { ptInClusters[k].clear(); }
findAssociatedCluster(src_img, n_cluster, clustersCenters, ptInClusters);
diffChange = adjustClusterCenters(src_img, n_cluster, clustersCenters, ptInClusters, oldCenter, newCenter);
}
Mat dst_img = applyFinalClusterTolmage(src_img, n_cluster, ptInClusters, clustersCenters);
//imshow("results", dst_img);
//waitKey(0);
return dst_img;
}
float max(float a, float b, float c) {
return ((a > b) ? (a > c ? a : c) : (b > c ? b : c));
}
float min(float a, float b, float c) {
return ((a < b) ? (a < c ? a : c) : (b < c ? b : c));
}
Mat MyBgr2Hsv(Mat src_img) {
float h, s, v;
float B, G, R;
float cmax, cmin, diff;
Mat dst_img(src_img.size(), src_img.type());
for (int r = 0; r < src_img.rows; r++) {
for (int c = 0; c < src_img.cols; c++) {
B = src_img.at<Vec3b>(r, c)[0] / 255.0;
G = src_img.at<Vec3b>(r, c)[1] / 255.0;
R = src_img.at<Vec3b>(r, c)[2] / 255.0;
cmax = max(R, G, B);
cmin = min(R, G, B);
diff = cmax - cmin;
if (cmax == cmin) h = 0;
else if (cmax == R) h = fmod((60 * ((G - B) / diff)), 360.0);
else if (cmax == G) h = fmod((60 * ((B - R) / diff) + 120), 360.0);
else if (cmax == B) h = fmod((60 * ((R - G) / diff) + 240), 360.0);
if (cmax == 0) s = 0;
else s = (diff / cmax) * 255;
v = cmax * 255;
dst_img.at<Vec3b>(r, c)[0] = (uchar)h;
dst_img.at<Vec3b>(r, c)[1] = (uchar)s;
dst_img.at<Vec3b>(r, c)[2] = (uchar)v;
}
}
return dst_img;
}
Mat MyinRange(Mat src_img, Scalar lower, Scalar upper) {
Mat dst_img(src_img.size(), src_img.type());
for (int r = 0; r < src_img.rows; r++) {
for (int c = 0; c < src_img.cols; c++) {
if ((lower[0] <= src_img.at<Vec3b>(r, c)[0] && src_img.at<Vec3b>(r, c)[0] <= upper[0])
&& (lower[1] <= src_img.at<Vec3b>(r, c)[1] && src_img.at<Vec3b>(r, c)[1] <= upper[1])
&& (lower[2] <= src_img.at<Vec3b>(r, c)[2] && src_img.at<Vec3b>(r, c)[2] <= upper[2])) {
dst_img.at<Vec3b>(r, c)[0] = 255;
dst_img.at<Vec3b>(r, c)[1] = 255;
dst_img.at<Vec3b>(r, c)[2] = 255;
}
else {
dst_img.at<Vec3b>(r, c)[0] = 0;
dst_img.at<Vec3b>(r, c)[1] = 0;
dst_img.at<Vec3b>(r, c)[2] = 0;
}
}
}
return dst_img;
}
pair<string, Mat> dominentColor(Mat hsv_img) {
double h, s, v;
int color[7] = { 0, 0, 0, 0, 0, 0, 0 };
vector<string> color_names = { "Red", "Orange", "Yellow", "Green", "Blue", "Purple", "red2" };
double min_s = 30;
double max_s = 255;
double min_v = 30;
double max_v = 255;
for (int y = 0; y < hsv_img.rows; y++) {
for (int x = 0; x < hsv_img.cols; x++) {
h = hsv_img.at<Vec3b>(y, x)[0] * 2; // Hue 값 조정
s = hsv_img.at<Vec3b>(y, x)[1];
v = hsv_img.at<Vec3b>(y, x)[2];
if (s < min_s || v < min_v) continue;
if ((h >= 0 && h <= 30) || (h >= 330 && h <= 360)) color[0]++;
else if (h >= 30 && h <= 90) color[1]++;
else if (h >= 90 && h <= 150) color[2]++;
else if (h >= 150 && h <= 210) color[3]++;
else if (h >= 210 && h <= 270) color[4]++;
else if (h >= 270 && h <= 330) color[5]++;
else if (h >= 270 && h <= 330) color[5]++;
else if (h >= 330 && h <= 360) color[6]++;
}
}
int max_index = max_element(color, color + 7) - color;
Scalar lower, upper;
switch (max_index) {
case 0: lower = Scalar(0, min_s, min_v); upper = Scalar(20, max_s, max_v); break;
case 1: lower = Scalar(20, min_s, min_v); upper = Scalar(50, max_s, max_v); break;
case 2: lower = Scalar(50, min_s, min_v); upper = Scalar(80, max_s, max_v); break;
case 3: lower = Scalar(80, min_s, min_v); upper = Scalar(110, max_s, max_v); break;
case 4: lower = Scalar(110, min_s, min_v); upper = Scalar(140, max_s, max_v); break;
case 5: lower = Scalar(140, min_s, min_v); upper = Scalar(170, max_s, max_v); break;
case 6: lower = Scalar(170, min_s, min_v); upper = Scalar(200, max_s, max_v); break;
}
return { color_names[max_index], MyinRange(hsv_img, lower, upper) };
}
Mat applyKMeans(const Mat& src_img, int k) {
// 이미지 데이터를 2차원 배열로 변환
Mat samples(src_img.rows * src_img.cols, 3, CV_32F);
for (int y = 0; y < src_img.rows; y++) {
for (int x = 0; x < src_img.cols; x++) {
for (int z = 0; z < 3; z++) {
samples.at<float>(y + x * src_img.rows, z) = src_img.at<Vec3b>(y, x)[z];
}
}
}
// k-means 클러스터링 수행
Mat labels;
Mat centers;
kmeans(samples, k, labels, TermCriteria(TermCriteria::EPS + TermCriteria::MAX_ITER, 10, 1.0), 3, KMEANS_PP_CENTERS, centers);
// 클러스터링 결과를 이미지로 변환
Mat result(src_img.size(), src_img.type());
for (int y = 0; y < src_img.rows; y++) {
for (int x = 0; x < src_img.cols; x++) {
int cluster_idx = labels.at<int>(y + x * src_img.rows, 0);
result.at<Vec3b>(y, x)[0] = centers.at<float>(cluster_idx, 0);
result.at<Vec3b>(y, x)[1] = centers.at<float>(cluster_idx, 1);
result.at<Vec3b>(y, x)[2] = centers.at<float>(cluster_idx, 2);
}
}
return result;
}
int main() {
/*
// 1번 문제
vector<string> filenames = { "orange.jpeg", "apple.jpeg", "kiwi.jpeg" };
for (const string& filename : filenames) {
Mat src_img = imread(filename, IMREAD_COLOR);
if (src_img.empty()) {
cerr << "Error loading image: " << filename << endl;
continue;
}
Mat hsv_img = MyBgr2Hsv(src_img);
pair<string, Mat> result = dominentColor(hsv_img);
string color_name = result.first;
Mat mask = result.second;
Mat result_img;
src_img.copyTo(result_img, mask);
cout << filename << "에서 가장 많은 색은 " << color_name << "입니다." << endl;
imshow("Source Image - " + filename, src_img);
imshow("Color Mask - " + filename, mask);
imshow("Filtered Image - " + filename, result_img);
waitKey(1000);
}
waitKey(0);
return 0;
*/
// 2번 문제
Mat src_img = imread("beach.jpg");
if (src_img.empty()) {
cerr << "Image load failed!" << endl;
return -1;
}
vector<int> ks = { 2, 4, 6, 8 }; // 다양한 k 값에 대해 실험
for (int k : ks) {
Mat clustered = applyKMeans(src_img, k);
string windowName = "Clustered Image k=" + to_string(k);
imshow(windowName, clustered);
}
waitKey(0);
return 0;
// 3번 문제
// 이미지 파일 목록
vector<string> filenames = { "orange.jpeg", "apple.jpeg", "kiwi.jpeg" };
for (const string& filename : filenames) {
Mat fruit_img = imread(filename);
if (fruit_img.empty()) {
cerr << "Failed to load image: " << filename << endl;
continue;
}
// K-means 클러스터링 수행
int k = 8; // 과일 이미지에 적용할 클러스터 수
Mat clustered_fruit_img = MyKmeans(fruit_img, k);
// 클러스터링 결과를 이미지로 디스플레이
string clusteredWindow = "Clustering: " + filename;
imshow(clusteredWindow, clustered_fruit_img);
// HSV 변환
Mat hsv_img = MyBgr2Hsv(fruit_img);
Mat hsv_clustered_img = MyBgr2Hsv(clustered_fruit_img);
// 가장 빈도 높은 색상 검출 및 마스크 생성 (원본 이미지)
pair<string, Mat> original_result = dominentColor(hsv_img);
string original_color_name = original_result.first;
Mat original_mask = original_result.second;
// 가장 빈도 높은 색상 검출 및 마스크 생성 (클러스터링된 이미지)
pair<string, Mat> clustered_result = dominentColor(hsv_clustered_img);
string clustered_color_name = clustered_result.first;
Mat clustered_mask = clustered_result.second;
// 원본 이미지에 마스크 적용
Mat masked_original_img;
fruit_img.copyTo(masked_original_img, original_mask);
// 클러스터링된 이미지에 마스크 적용
Mat masked_clustered_img;
clustered_fruit_img.copyTo(masked_clustered_img, clustered_mask);
// 마스킹된 결과를 디스플레이
string original_mask_window = "Original Mask " + filename;
imshow(original_mask_window, masked_original_img);
string clustered_mask_window = "Clustered Mask " + filename;
imshow(clustered_mask_window, masked_clustered_img);
cout << filename << "에서 원본 이미지에서 가장 많은 색은 " << original_color_name << "이고, "
<< "클러스터링된 이미지에서 가장 많은 색은 " << clustered_color_name << "입니다." << endl;
// 사용자가 각 이미지를 확인할 수 있도록 잠시 대기
waitKey(0); // 각 이미지를 차례로 확인
}
return 0;
}
1번 문제 설명
1번 문제는 과일 사진에서 지배적인 색상을 식별하고 해당 색상에 기반한 분할(segmentation)을 수행하는 문제이다. 먼저 BGR 색상 공간에서 입력된 이미지를 HSV 색상 공간으로 변환하여 각 픽셀의 색상, 채도, 명도를 추출한다. 그런 다음, 특정 색상 범위에 해당하는 지배적인 색상을 찾아내고 이를 기준으로 마스크를 생성한다. 마스크는 해당 색상의 픽셀을 강조하고 나머지를 배제하는 역할을 한다. 생성된 마스크를 활용해 입력 이미지에서 지배적인 색상만을 분리하고, 이를 출력으로 제공한다. 이를 통해 과일의 대표적인 색상을 파악하고 이를 기반으로 특정 색상의 과일 부분을 추출할 수 있다. 마지막으로 K-평균 클러스터링을 통해 입력 이미지의 색상을 k개의 군집으로 그룹화하여 시각적으로 구분된 결과를 얻을 수 있다.
코드를 상세하게 살펴보면 우선, MyBgr2Hsv 함수는 입력된 이미지를 BGR에서 HSV 색상 공간으로 변환한다. 각 픽셀의 B, G, R 값을 활용해 최대값과 최소값을 구하고 이를 통해 Hue, Saturation, Value의 값을 계산한다. Hue는 색상, Saturation은 채도, Value는 명도에 해당하는데, 이 값들을 0~255 범위의 정수로 변환해 새로운 이미지로 만든다.
이후 dominentColor 함수는 HSV 이미지에서 지배적인 색상을 찾고 해당 색상의 범위를 기준으로 마스크를 생성한다. 우선, 픽셀별로 특정 범위의 채도와 명도에 맞지 않는 경우를 제외하고, 남은 픽셀의 Hue 값을 통해 미리 정의된 색상 범위에 따라 색상별로 개수를 센다. 그런 다음, 가장 많은 픽셀을 차지하는 색상의 인덱스를 찾고 해당 색상에 맞는 범위를 lower와 upper로 정의한다.
마지막으로, MyinRange 함수를 사용해 이 범위에 속하는 픽셀을 모두 흰색으로 표시하고 나머지는 검정색으로 처리하는 마스크를 생성한다. 이 마스크를 원본 이미지에 적용해 지배적인 색상만 분리한다.
1번 문제 결과
Orange.jpeg에 대해서 Orange가 가장 많은 색으로 추출이되고 mask도 잘 생성이 되어 오렌지 부분만 잘 segmentation이 된 것을 볼 수 있다. Apple, kiwi에 대해서도 색이 잘 추출되고 segmentation되는 것을 확인할 수 있다. 그러나 과일의 하얀 부분들은 색이 다르기 때문에 masking되어버려 중간중간 이미지가 날라간 것을 볼 수 있다.
2번 문제 설명
문제에서는 OpenCV를 사용하여 이미지를 K-평균(K-means) 클러스터링으로 분할하는 실험을 진행한다. `applyKMeans` 함수는 이미지 데이터를 opencv의 내장 함수를 이용하여 k개의 색상 클러스터로 그룹화하여 결과 이미지를 생성한다. 이를 위해 먼저 이미지의 픽셀 값을 2차원 배열로 변환해 샘플로 구성한 뒤, K-평균 클러스터링 알고리즘을 적용해 라벨과 클러스터 중심을 찾는다. 그 결과를 사용해 각 픽셀을 가장 가까운 클러스터의 중심 색상으로 치환하여 결과 이미지를 얻는다.
메인 함수에서는 다양한 k 값(2, 4, 6, 8)을 시도하여 클러스터링 결과를 비교한다. `applyKMeans` 함수를 호출해 각각의 k 값에 대해 이미지를 클러스터링하고, 이를 시각적으로 확인하기 위해 OpenCV의 `imshow` 함수를 사용해 결과를 출력한다. 이를 통해 k 값에 따라 이미지의 색상 분포가 어떻게 그룹화되고 시각적으로 변화하는지 알 수 있다.
2번 문제 결과
원본 beach.jpg
클러스터링 결과
2,4,6,8개의 클러스터로 색상들이 그룹화되어 표현되는 것을 볼 수 있다. 클러스터의 수가 올라갈수록 원본에 대한 왜곡이 줄어들고 사진의 표현력이 올라가는 것을 볼 수 있다.
3번 문제 설명
3번 문제의 코드는 과일 이미지를 K-평균 클러스터링을 통해 분할하고, 지배적인 색상을 찾아 마스크를 생성하는 과정을 구현한 프로그램이다. 먼저, 이미지 파일 목록에 포함된 각 과일 이미지를 읽어 들인 후, `MyKmeans` 함수를 사용해 이미지 색상을 k개의 클러스터로 그룹화한다. 여기서는 과일 이미지의 색상을 효과적으로 분류하기 위해 클러스터 수 k를 8로 설정하였다.
클러스터링된 이미지는 원본 이미지와 함께 HSV 색상 공간으로 변환된다. 그런 다음, `dominentColor` 함수를 통해 두 이미지에서 가장 지배적인 색상을 찾아내고 해당 색상의 범위에 맞는 마스크를 생성한다. 원본 및 클러스터링된 이미지에 생성된 마스크를 적용해 해당 색상만 분리된 이미지를 출력한다.
결과적으로, 원본 이미지와 클러스터링된 이미지에서 각각 지배적인 색상을 추출해 두 이미지 간의 색상 분포 차이를 확인할 수 있다. 각 이미지에서 가장 지배적인 색상 이름을 출력하고, 시각적으로 원본과 클러스터링된 이미지의 차이를 명확히 확인할 수 있도록 마스킹된 결과도 함께 디스플레이한다. 이 코드를 통해 K-평균 클러스터링을 사용한 색상 분할과 지배적인 색상의 마스킹 기법을 활용해 이미지의 특정 색상 범위를 효과적으로 추출하고 비교할 수 있다.
3번 문제 결과
클러스터링 후에 지배적인 색을 이용하여 segmentation을 수행하면 더 나은 결과가 나오는 것을 볼 수 있다. 특히 오렌지와 사과에서 원본에 바로 적용하였을 때는 중간중간 하얀부분이 날라갔었는데 클러스터링을 하고 진행하면 그런 문제가 거의 해결되는 것을 볼 수 있다. 물론 두 결과 모두 지배적인 색을 출력하는 것에서는 같은 결과가 나오는 것을 볼 수 있다.
'Quality control (Univ. Study) > Digital Image Processing' 카테고리의 다른 글
DIP 실습 - Mean-shift / GrabCut (1) | 2024.05.16 |
---|---|
Digital Image Processing - MRF / Graph Cuts (1) | 2024.05.15 |
DIP 실습 - Band pass filter / Frequency domain (0) | 2024.05.14 |
DIP 실습 - Gaussian / Sobel / Gaussian Pyramid / Laplacian Pyramid (1) | 2024.05.13 |
Digital Image Processing - Clustering / Segmentation (0) | 2024.05.08 |