SoFunction
Updated on 2024-11-16

opencv color filtering leaves only the red areas of the picture operation

As shown in the image, this time you need to find the red scale of the tape measure in the image, so you need to do a filter on the image, leaving only the red part.

The idea at first was to find the RGB values separately and then just find the part of the red area to keep, but it seems to be difficult to determine the range of RGB values for the red area, so you have to convert the image into HSV space.

Just use the cvCvtColor function directly in opencv.

IplImage* hsv = cvCreateImage( cvGetSize(image), 8, 3 );

cvCvtColor(image,hsv,CV_BGR2HSV);

The H range of opencv is 0~180, the H range of red is about (0~8) ∪ (160,180), S is saturation, generally is greater than a value, S is too low is gray (reference value S>80), V is brightness, too low is black, too high is white (reference value 220>V>50).

So the next thing to do is to traverse the image and get the H,S,V components of each pixel point of the image and then do the judgment and keep the ones that satisfy the conditions and assign the ones that don't to black.

I am using IplImage in opencv to store the image.

IplImage gets pixel points as follows:

CvScalar s_hsv = cvGet2D(hsv, j, i);//Get the value of HSV with pixel point (i, j), i is the width value, j is the height value.

IplImage assigns values to pixel points as follows:

CvScalar s;

cvSet2D(hsv, j ,i, s);//assign value to the pixel point at (i,j)

Obtain the H,S,V components respectively, and note that the image is transformed with BGR2HSV,so [0] is the value of B or H, [1] is the value of G or S, and [2] is the value of R or V.

Because my brother likes to use CvMat, so the input are changed to CvMat, the use of inputImage is the hope that the filtered image, outputImage for the output image, because outputImage will be in the function of the space application and assignment, so pass the parameter directly when it is set to NULL can be.

Another thing to note is that since you are experimenting with color images, if the incoming image is not a 3-channel color image, then you will get a memory error.

The following ways of opening images or creating images are single-channel ways and will result in memory errors.

IplImage *input = cvLoadImage(path, 0),
CvMat* M = cvCreateMat(4,4,CV_32FC1); //or 8UC1, because C1 means nChannel = 1, i.e. single channel.

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);//get the value of HSV with pixel point (j, i) point
 /*
 The H range of opencv is 0~180, the H range of red color is about (0~8) ∪ (160,180)
 S is the saturation, generally is greater than a value, S is too low is gray (reference value S>80).
 V is brightness, too low is black, too high is white (reference value 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)))
 {
 [0] =0;
 [1]=0;
 [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);
}

There is one more thing to note about the function, the H component I obtained is (0,8), (120,180), the S and V components are not filtered, if the filtering according to the comment part of the results are not very good.

The results are shown in the figure:

Additional knowledge:opencv implements image to remove a single color background

reasoning

Since the background is a fixed color, it's easy to filter out the background and then just set it to white and completely transparent.

coding

#coding=utf-8
import cv2 as cv
bg_color = [197, 102, 6]
threshold = 3000

def calc_diff(pixel):
'''
Calculate the sum of squared deviations of pixel from the background as a measure of how similar the current pixel point is to the background
'''
  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 = (image_path)
  logo = (logo, cv.COLOR_BGR2BGRA) #Convert images to BGRA format with transparent channels
  h, w = [0:2]
  for i in range(h):
    for j in range(w):
      if calc_diff(logo[i][j]) < threshold:
      # If logo[i][j] is the background, set its color to white and make it completely transparent.
        logo[i][j][0] = 255
        logo[i][j][1] = 255
        logo[i][j][2] = 255
        logo[i][j][3] = 0
 
  ("./logo_rmbg.png", logo)
        
if __name__ == '__main__':
  remove_bg()

Usage

Modify bg_color in line 5 to be the bgr value of the image background, and threshold in line 6 (the larger the threshold, the more pixels are covered).

Effect:

emmm, it turns out that the color near the background wasn't strictly a background color, and it was much better when the words were filled in later.

Above this opencv of color filtering only leave the picture in the red area of the operation is all I have shared with you, I hope to be able to give you a reference, and I hope you support me more.