Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

I want to change the colors in image with python from specific color range to another color

enter image description here

I want to change the brown areas to RED (or another color). Just I don't know how to get the ranges for brown and put them in python code. I know how to change a single color, but not a range of colors. Any Ideas? Thanks

like image 225
George Tanev Avatar asked May 07 '18 08:05

George Tanev


2 Answers

This should give you an idea - it is pretty well commented:

#!/usr/local/bin/python3
import cv2 as cv
import numpy as np

# Load the aerial image and convert to HSV colourspace
image = cv.imread("aerial.png")
hsv=cv.cvtColor(image,cv.COLOR_BGR2HSV)

# Define lower and uppper limits of what we call "brown"
brown_lo=np.array([10,0,0])
brown_hi=np.array([20,255,255])

# Mask image to only select browns
mask=cv.inRange(hsv,brown_lo,brown_hi)

# Change image to red where we found brown
image[mask>0]=(0,0,255)

cv.imwrite("result.png",image)

enter image description here


How did I determine the limits for "brown"? I located a brown area in the image, and cropped it out to remove everything else. Then I resized it to 1x1 to average all the shades of brown in that area and converted it to HSV colourspace, I printed that and took the value for Hue which was 15 and went +/-5 to give a range of 10-20. Increase the range to 8-22 to select a wider range of hues.

HSV/HSL colourspace is described on Wikipedia here.

Keywords: Image processing, Python, OpenCV, inRange, range of colours, prime.

like image 136
Mark Setchell Avatar answered Oct 16 '22 20:10

Mark Setchell


I would like to propose a different approach. However, this will work only for a range of certain dominant colors (red, blue, green and blue). I am focusing on the red colored regions present in the image in question.

Background:

Here I am using LAB color space where:

  • L-channel: expresses the brightness in the image
  • A-channel: expresses variation of color in the image between red and green
  • B-channel: expresses variation of color in the image between yellow and blue

Since I am interested in the red region, I will choose the A-channel for further processing.

Code:

img = cv2.imread('image_path')

# convert to LAB color space
lab = cv2.cvtColor(img, cv2.COLOR_BGR2LAB)

# A-channel
cv2.imshow('A-channel', lab[:,:,1])

enter image description here

If you look at the image closely, the bright regions correspond to the red color in the original image. Now when we threshold it, we can isolate it completely:

th = cv2.threshold(lab[:,:,1],127,255,cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]

enter image description here

Using the th image as mask, we give a different color to the corresponding regions in white:

# create copy of original image
img1=img.copy()
# highlight white region with different color
img1[th==255]=(255,255,0)

enter image description here

Here are both the images stacked beside each other:

enter image description here

You can normalize the A-channel image to better visualize it:

dst = cv2.normalize(lab[:,:,1], dst=None, alpha=0, beta=255,norm_type=cv2.NORM_MINMAX, dtype=cv2.CV_8U)

enter image description here

In this way, there is no need to look for range in HSV space when working with dominant colors. Exploring the B-channel can help isolate blue and yellow colored regions.

like image 27
Jeru Luke Avatar answered Oct 16 '22 22:10

Jeru Luke