1 #include <opencv2/opencv.hpp>
2 #include <iostream>
3
4 using namespace cv;
5 using namespace std;
6
7 Mat mat_to_samples(Mat &image);
8 int main(int argc, char** argv) {
9 Mat src = imread("tx.png");
10 if (src.empty()) {
11 printf("could not load image...\n");
12 return -1;
13 }
14 namedWindow("输入图像", CV_WINDOW_AUTOSIZE);
15 imshow("输入图像", src);
16
17 // 组装数据
18 Mat points = mat_to_samples(src);
19
20 // 运行KMeans
21 int numCluster = 4;
22 Mat labels;
23 Mat centers;
24 TermCriteria criteria = TermCriteria(TermCriteria::EPS + TermCriteria::COUNT, 10, 0.1);
25 kmeans(points, numCluster, labels, criteria, 3, KMEANS_PP_CENTERS, centers);
26
27 // 去背景+遮罩生成
28 Mat mask=Mat::zeros(src.size(), CV_8UC1);
29 int index = src.rows*2 + 2;
30 int cindex = labels.at<int>(index, 0);
31 int height = src.rows;
32 int width = src.cols;
33 //Mat dst;
34 //src.copyTo(dst);
35 for (int row = 0; row < height; row++) {
36 for (int col = 0; col < width; col++) {
37 index = row*width + col;
38 int label = labels.at<int>(index, 0);
39 if (label == cindex) { // 背景
40 //dst.at<Vec3b>(row, col)[0] = 0;
41 //dst.at<Vec3b>(row, col)[1] = 0;
42 //dst.at<Vec3b>(row, col)[2] = 0;
43 mask.at<uchar>(row, col) = 0;
44 } else {
45 mask.at<uchar>(row, col) = 255;
46 }
47 }
48 }
49 imshow("mask-遮罩", mask);
50
51 // 腐蚀 + 高斯模糊
52 Mat k = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));//用3*3像素进行腐蚀(减少3*3)
53 erode(mask, mask, k);
54 imshow("腐蚀-mask", mask);
55 GaussianBlur(mask, mask, Size(3, 3), 0, 0);//用3*3像素进行高斯模糊(增加3*3) 所以边界不变
56 imshow("高斯模糊-mask", mask);
57
58 // 通道混合
59 RNG rng(12345);//随机数
60 Vec3b color;
61 color[0] = 217;//rng.uniform(0, 255);
62 color[1] = 60;// rng.uniform(0, 255);
63 color[2] = 160;// rng.uniform(0, 255);
64 Mat result(src.size(), src.type());
65
66 double w = 0.0;
67 int b = 0, g = 0, r = 0;
68 int b1 = 0, g1 = 0, r1 = 0;
69 int b2 = 0, g2 = 0, r2 = 0;
70
71 for (int row = 0; row < height; row++) {
72 for (int col = 0; col < width; col++) {
73 int m = mask.at<uchar>(row, col);
74 if (m == 255) {
75 result.at<Vec3b>(row, col) = src.at<Vec3b>(row, col); // 前景
76 }
77 else if (m == 0) {
78 result.at<Vec3b>(row, col) = color; // 背景
79 }
80 else {
81 w = m / 255.0;
82 b1 = src.at<Vec3b>(row, col)[0];
83 g1 = src.at<Vec3b>(row, col)[1];
84 r1 = src.at<Vec3b>(row, col)[2];
85
86 b2 = color[0];
87 g2 = color[1];
88 r2 = color[2];
89
90 b = b1*w + b2*(1.0 - w);
91 g = g1*w + g2*(1.0 - w);
92 r = r1*w + r2*(1.0 - w);
93
94 result.at<Vec3b>(row, col)[0] = b;
95 result.at<Vec3b>(row, col)[1] = g;
96 result.at<Vec3b>(row, col)[2] = r;
97 }
98 }
99 }
100 imshow("背景替换", result);
101
102 waitKey(0);
103 return 0;
104 }
105
106 Mat mat_to_samples(Mat &image) {
107 int w = image.cols;
108 int h = image.rows;
109 int samplecount = w*h;
110 int dims = image.channels();
111 Mat points(samplecount, dims, CV_32F, Scalar(10));
112
113 int index = 0;
114 for (int row = 0; row < h; row++) {
115 for (int col = 0; col < w; col++) {
116 index = row*w + col;
117 Vec3b bgr = image.at<Vec3b>(row, col);
118 points.at<float>(index, 0) = static_cast<int>(bgr[0]);
119 points.at<float>(index, 1) = static_cast<int>(bgr[1]);
120 points.at<float>(index, 2) = static_cast<int>(bgr[2]);
121 }
122 }
123 return points;
124 }