OpenCV颜色过滤实战:提取红色区域与去除固定背景
本文详解如何利用OpenCV将图像转换至HSV空间以精准提取红色刻度,通过遍历像素并设定H、S、V阈值实现红色区域保留。同时补充了基于固定颜色背景去除的算法思路与代码,通过计算像素与背景色的离差,将匹配背景设为透明,适用于图像去底场景。
OpenCV提取图像红色区域
如图所示,本次任务的目标是从图像中识别并提取卷尺的红色刻度,因此需要对图像进行颜色过滤处理,仅保留红色部分。

起初考虑直接通过RGB值来界定红色区域,但发现确定红色在RGB空间中的取值范围较为困难。因此,更有效的策略是将图像转换到HSV色彩空间中进行处理。
在OpenCV中,可以直接调用cvCvtColor函数完成色彩空间转换。
IplImage* hsv = cvCreateImage( cvGetSize(image), 8, 3 );
cvCvtColor(image,hsv,CV_BGR2HSV);
在OpenCV中,H(色相)的取值范围是0~180。红色的H值大致分布在(0~8)和(160,180)两个区间。S(饱和度)通常需大于某个阈值,若S过低则呈现灰色(参考值S>80)。V(亮度)过低表现为黑色,过高则为白色(参考值50<V<220)。
接下来的步骤是遍历图像,获取每个像素点的H、S、V分量,进行条件判断:满足红色区域条件的像素予以保留,不满足条件的像素则赋值为黑色。
此处使用OpenCV中的IplImage结构体来存储图像数据。
IplImage获取像素点数据的方法如下:
CvScalar s_hsv = cvGet2D(hsv, j, i);//获取坐标为(i, j)的像素点的HSV值,其中i代表宽度方向,j代表高度方向
IplImage对像素点进行赋值的方法如下:
CvScalar s;
cvSet2D(hsv, j ,i, s);//对坐标(i,j)处的像素点进行赋值
分别提取H、S、V分量时需注意,由于图像是从BGR转换为HSV,因此s.val[0]对应H值(原B值),s.val[1]对应S值(原G值),s.val[2]对应V值(原R值)。
鉴于使用者偏好使用CvMat,输入参数已调整为CvMat类型。其中inputImage为待过滤的源图像,outputImage为输出图像。由于outputImage在函数内部会进行内存申请与赋值,因此在调用函数时可直接将其设为NULL。
需注意,本实验针对彩色图像进行。若传入的图片不是3通道的彩色图像,程序将引发内存错误。
以下打开或创建图片的方式均为单通道模式,直接运行会导致内存错误。
IplImage *input = cvLoadImage(path, 0),
CvMat* M = cvCreateMat(4,4,CV_32FC1); //或是8UC1, 因为C1表示nChannel = 1,也就是单通道
void colorFilter(CvMat *inputImage, CvMat *&outputImage)
{
int i, j;
IplImage* image = cvCreateImage(cvGetSize(inputImage), 8, 3);
cvGetImage(inputImage, image);
IplImage* hsv = cvCreateImage( cvGetSize(image), 8, 3 );
cvCvtColor(image,hsv,CV_BGR2HSV);
int width = hsv->width;
int height = hsv->height;
for (i = 0; i < height; i++)
for (j = 0; j < width; j++)
{
CvScalar s_hsv = cvGet2D(hsv, i, j);//获取像素点为(j, i)点的HSV的值
/*
opencv 的H范围是0~180,红色的H范围大概是(0~8)∪(160,180)
S是饱和度,一般是大于一个值,S过低就是灰色(参考值S>80),
V是亮度,过低就是黑色,过高就是白色(参考值220>V>50)。
*/
CvScalar s;
if (!(((s_hsv.val[0]>0)&&(s_hsv.val[0]<8)) || (s_hsv.val[0]>120)&&(s_hsv.val[0]<180)))
{
s.val[0] =0;
s.val[1]=0;
s.val[2]=0;
cvSet2D(hsv, i ,j, s);
}
}
outputImage = cvCreateMat( hsv->height, hsv->width, CV_8UC3 );
cvConvert(hsv, outputImage);
cvNamedWindow("filter");
cvShowImage("filter", hsv);
waitKey(0);
cvReleaseImage(&hsv);
}
关于该函数的另一个说明:H分量的筛选范围设定为(0,8)和(120,180),而S与V分量未做额外筛选。若按照代码注释中的条件进行严格筛选,处理效果并不理想。
处理结果如图所示:

OpenCV去除固定颜色背景
补充知识:利用OpenCV实现图像单一颜色背景的去除。
思路分析

由于背景颜色固定,很容易通过颜色筛选将背景分离,并将其设置为白色且完全透明。
代码实现
#coding=utf-8
import cv2 as cv
bg_color = [197, 102, 6]
threshold = 3000
def calc_diff(pixel):
'''
计算pixel与背景的离差平方和,作为当前像素点与背景相似程度的度量
'''
return (pixel[0]-bg_color[0])**2 + (pixel[1]-bg_color[1])**2 + (pixel[2]-bg_color[2])**2
def remove_bg():
image_path = './logo.png'
logo = cv.imread(image_path)
logo = cv.cvtColor(logo, cv.COLOR_BGR2BGRA) #将图像转成带透明通道的BGRA格式
h, w = logo.shape[0:2]
for i in range(h):
for j in range(w):
if calc_diff(logo[i][j]) < threshold:
#若果logo[i][j]为背景,将其颜色设为白色,且完全透明
logo[i][j][0] = 255
logo[i][j][1] = 255
logo[i][j][2] = 255
logo[i][j][3] = 0
cv.imwrite("./logo_rmbg.png", logo)
if __name__ == '__main__':
remove_bg()
使用方法说明
需修改第5行的bg_color参数为图片背景色的BGR值,以及第6行的threshold阈值(threshold值越大,被覆盖处理的像素范围越广)。
处理效果:

实际测试表明,背景附近的颜色并非严格的背景色,导致边缘处理存在瑕疵。后续通过填充文字颜色,效果得到了改善。

以上关于OpenCV颜色过滤提取红色区域及背景去除的操作即为全部内容,希望能对读者有所帮助,欢迎支持本站。
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













