在图像分割问题中,图像的灰度值做为一个重要的特征,有助于提取感兴趣的区域。
提出一个问题:
给定一张自然图像,如何在复杂的背景中提取文字,并将文字与图分离?
提取颜色分量有多种方法,本文提供两种思路:
(1) 遍历整个图像,通过阈值法提取某个颜色分量
(2) 调用OPENCV中提供的split()函数,实现颜色通道分离
方法比较:
彩色图像中一共有pow(2.0,8) * pow(2.0,8)种颜色,用split()函数会提取全局范围内德颜色分量,而阈值法可以自定义阈值,从而实现小范围内的颜色分量提取。
对于本文给出的图像,用阈值法提取文字的效果更好。效果图如下:
本文基于以上方法,分别实现阈值处理和split()函数。具体实现代码如下,且在vs2010测试通过。
#include "opencv2/core/core.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/photo/photo.hpp"
#include <iostream>
using namespace std;
using namespace cv;
//该方法可能产生误检点,需要使用形态学后处理
void GetRedComponet(Mat srcImg)
{
//如果直接对srcImg处理会改变main()函数中的实参
Mat dstImg = srcImg.clone();
Mat_<Vec3b>::iterator it = dstImg.begin<Vec3b>();
Mat_<Vec3b>::iterator itend = dstImg.end<Vec3b>();
for(; it != itend; it++)
{
if((*it)[2] > 190)//对红色分量做阈值处理
{
(*it)[0] = 0;
(*it)[1] = 0;
//(*it)[2] = 255;//红色分量保持不变
}
else
{
(*it)[0] = 0;
(*it)[1] = 0;
(*it)[2] = 0;
}
}
imshow("红色分量图 by 阈值法",dstImg);
waitKey(0);
}
//将整幅图中的红色分量都提取出来
void GetRedComponetBySplit(Mat srcImg)
{
Mat imgROI;
vector<Mat>channels;
split(srcImg,channels);
Mat blueComponet = channels.at(0);
Mat greenComponet = channels.at(1) ;
blueComponet = Mat::zeros(srcImg.size(),CV_8UC1);//Mat相当于指针,会对chnnels.at(0)重新赋值
greenComponet = Mat::zeros(srcImg.size(),CV_8UC1);
merge(channels,imgROI);//仅仅保留红色分量,其他分量赋值为0
imshow("红色分量图 by split()函数",imgROI);
waitKey(0);
}
int main(int argc,char* argv[])
{
Mat srcImg;
srcImg = imread("D:/openCV/data/naturalImage/data/opencv.jpg",1);
GetRedComponet(srcImg);
GetRedComponetBySplit(srcImg);
return 0;
}