OpenCV颜色过滤实战:提取红色区域与去除固定背景

月亮慢半拍
月亮慢半拍
发布时间:2026-10-14| 6人浏览过
原创

本文详解如何利用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颜色过滤提取红色区域及背景去除的操作即为全部内容,希望能对读者有所帮助,欢迎支持本站。

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。