今天介绍一下对一幅图片的操作,首先第一个例子就是给萌萌猫带上一个小铃铛。
给出两幅原始图片:
Figure 1
Figure 2
如何把这两张图片组合起来呢?第一个想法就是把第二张图直接拼接到萌萌猫脖子上,下面给出代码:
#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
using namespace cv;
using namespace std;
const int dx = 260;
const int dy = 75;
int main() {
Mat cat = imread("/Users/apathetically/code/C++/opencv/opencv/cat.png");
Mat bell = imread("/Users/apathetically/code/C++/opencv/opencv/Bell.png");
if(cat.empty()) {
cout << "いいえ" << endl;
return -1;
}
if(bell.empty()) {
cout << "いいえ" << endl;
return -1;
}
for(int i = dx;i < dx + bell.rows;i ++) {
for(int j = dy;j < dy + bell.cols;j ++) {
cat.at<Vec3b>(i, j) = bell.at<Vec3b>(i - dx, j - dy);
}
}
imshow("mypic", cat);
waitKey();
return 0;
}
这个代码运行结果为:
经过一次又一次的试探,铃铛终于被安置到了合适的位置,但是,出现的问题就是铃铛图片中存在的空白覆盖掉了猫的图片。如何解决这个问题?
我的做法就是过滤掉铃铛图片中的白色,上一篇blog讲到了对于三通道的图片,每个像素点是一个包含三个元素的向量。而我们知道白色对应的三原色为[255, 255, 255],考虑到误差,我将铃铛图片三个颜色值都大于200的像素点过滤掉,即这个像素点仍然采用猫图片的像素点,而假若不符合这个的条件,就采用铃铛的图片。
修改代码如下:
cat.at<Vec3b>(i, j) = bell.at<Vec3b>(i - dx, j - dy);
这行代码之前加一个判断语句:
if(!(bell.at<Vec3b>(i - dx, j - dy)[0] > 200
&& bell.at<Vec3b>(i - dx, j - dy)[1] > 200
&& bell.at<Vec3b>(i - dx, j - dy)[2] > 200))
此时代码为:
#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
using namespace cv;
using namespace std;
const int dx = 260;
const int dy = 75;
int main() {
Mat cat = imread("/Users/apathetically/code/C++/opencv/opencv/cat.png");
Mat bell = imread("/Users/apathetically/code/C++/opencv/opencv/Bell.png");
if(cat.empty()) {
cout << "いいえ" << endl;
return -1;
}
if(bell.empty()) {
cout << "いいえ" << endl;
return -1;
}
for(int i = dx;i < dx + bell.rows;i ++) {
for(int j = dy;j < dy + bell.cols;j ++) {
if(!(bell.at<Vec3b>(i - dx, j - dy)[0] > 200 && bell.at<Vec3b>(i - dx, j - dy)[1] > 200
&& bell.at<Vec3b>(i - dx, j - dy)[2] > 200)) {
cat.at<Vec3b>(i, j) = bell.at<Vec3b>(i - dx, j - dy);
}
}
}
imshow("mypic", cat);
waitKey();
return 0;
}
运行的结果为:
这样就成功把铃铛中的空白过滤掉挂到萌萌猫脖子上啦。
现在来解释一下代码:
const int dx = 260;
const int dy = 75;
这两行代码设置了铃铛图片在猫图片中的偏移量。
if(!(bell.at<Vec3b>(i - dx, j - dy)[0] > 200
&& bell.at<Vec3b>(i - dx, j - dy)[1] > 200
&& bell.at<Vec3b>(i - dx, j - dy)[2] > 200))
这个代码块的作用是排除了图片中接近空白的像素。
cat.at<Vec3b>(i, j) = bell.at<Vec3b>(i - dx, j - dy);
这个语句表示将铃铛中符合条件的像素覆盖到对应猫图片上。至此在萌萌猫脖子上挂铃铛的任务就完成啦。
之后有时间补接下来的图片拼接例子。