17

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

Jeru Luke
  • 20,118
  • 13
  • 80
  • 87
George Tanev
  • 191
  • 1
  • 3
  • 7
  • 1
    Change/read image to HSV-color space array and manipulate only colors (hues) in brown color band. – Mika72 May 07 '18 at 08:49
  • You could also use the [`inRange`](https://docs.opencv.org/3.4.1/d2/de8/group__core__array.html#ga48af0ab51e36436c5d04340e036ce981) function to extract a mask based on your color range, then use the mask to change the pixel values in the image. – zindarod May 07 '18 at 09:39

2 Answers2

50

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.

Mark Setchell
  • 191,897
  • 31
  • 273
  • 432
2

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.

Jeru Luke
  • 20,118
  • 13
  • 80
  • 87