标签:
这次区别于证件照,我试着编写了一下在复杂背景下分离纯色物体的系统,因为只是简单的编程,所以结果有待优化,先分析一下实验环境:
这次的背景杂乱,虽然主体是粉色主导,但是因为光照不统一,色域跨度较大,倒影中也有粉色痕迹,杯壁上有花纹,这种情况下边缘检测误差很大。
为了让计算机更好的识别主体颜色,要先将RGB色域转换为HSV色域,在HSV色域中,红色的H值在(0,3)U(156,180)中。粉色的S值饱和度不高,但是比白色要高很多,区间在(50,150)以内。
V代表Value,只有黑色或偏黑的颜色V值会偏低,这里我们只要设定一个稍高的阈值就可以了。
第一步是大体分离出主体部分,满足条件的颜色区域会被标记为白色(255)其余为黑色(0):
左边这张图是Hue单通道的检测,因为在Opencv中,Hue通道的取值范围是0-180,红色在180左右的位置,所以发白,而杯体其他部分的红色较深,集中在0-5内,所以显示为黑色。
将两个区域相并,并加上对value与Saturation的限制,右图既是HSVmask的结果。
void ToHSV(cv::Mat image, cv::Mat result) //产出是一个mask { cv::Mat hsv_image; //转HSV hsv_image.create(image.size(), image.type()); cv::cvtColor(image, hsv_image, CV_BGR2HSV); vector<cv::Mat> channels; cv::split(hsv_image, channels); int num_row = image.rows; int num_col = image.cols; for (int r = 0; r < num_row; r++) { const cv::Vec3b* curr_r_image = image.ptr<const cv::Vec3b>(r); const uchar* curr_r_hue = channels[0].ptr<const uchar>(r); const uchar* curr_r_satur = channels[1].ptr<const uchar>(r); const uchar* curr_r_value = channels[2].ptr<const uchar>(r); uchar* curr_r_result = result.ptr<uchar>(r); for (int c = 0; c < num_col; c++) { if (((curr_r_hue[c] <= 2 && curr_r_hue[c] >= 0) || (curr_r_hue[c] <= 180 && curr_r_hue[c] >= 150)) && curr_r_value[c]>130 && curr_r_satur[c]>35 && curr_r_satur[c]<150) //找颜色 { curr_r_result[c] = 255; } else { curr_r_result[c] = 0; } } } }
这个方法中,参数第一个为3通道RGB图像,第二个参数为单通道的灰度二值图像。
因为这个mask还有一些瑕疵,为了去除这部分瑕疵我们需要使用形态学滤波器:
void Homography(cv::Mat image, cv::Mat Opened) //mask { cv::Mat element_9(9, 9, CV_8U, cv::Scalar(1)); cv::morphologyEx(image, Opened, cv::MORPH_OPEN, element_9); }
形态学滤波只针对二值图像,因此输入输出都是二值图像,structure element为9X9,意味着长宽不足9的像素块会被抹去,结果如下:
将mask运用到原图像上:
void copymask(cv::Mat image, cv::Mat openmask, cv::Mat result) { int num_row = image.rows; int num_col = image.cols; for (int r = 0; r < num_row; r++) { uchar* curr_r_open = openmask.ptr<uchar>(r); cv::Vec3b* curr_r_image = image.ptr<cv::Vec3b>(r); cv::Vec3b* curr_r_result = result.ptr<cv::Vec3b>(r); for (int c = 0; c < num_col; c++) { if (curr_r_open[c] ==255) { curr_r_result[c] = curr_r_image[c]; } } } }
结果如下:
可以看到损失了一部分,损失的这部分就是原图中的高光区域,这些区域的颜色因为光的照射变为白色,不好从颜色上区分,也是这种方法的一个盲点。
还有一种区分的办法为边缘检测,在OpenCV中,边缘检测极易实现,但是图片背景过于复杂的话则会产生许多干扰:
void edgedetection(cv::Mat image, cv::Mat edge) { cv::morphologyEx(image, edge, cv::MORPH_GRADIENT, cv::Mat()); int threshold =240; cv::threshold(edge, edge, threshold, 255, cv::THRESH_BINARY); }
结果如下:
可以看到被子的倒影对于边缘检测产生了很大的影响,若杯体本身跟后边背景的颜色差异不大的话,也很难被检测到。
标签:
原文地址:http://www.cnblogs.com/wangxinyu0628/p/5928824.html