2

I have a satellite image and am trying to isolate one roof based on it's color. My plan is to take the color of a chosen point in the image, and create a slightly lighter > slightly darker range from it (allowing for variation based on sun and shade) and to remove all colors other than those within the range.

Then I need to keep only the color area that contains the originally selected point.

Below is an example sample image, color range and final image I would like to achieve edited manually in photoshop.

I have also had trouble converting an RGB color to HSV values that produce predictable results in the following script. I have tried following various guides for green-screening using python, e.g: this and this.

I have been trying to use the following but am running into a few issues:

img = cv2.imread("static.jpg".format(latlon, zoom))
img_hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)

# light color in RGB = [153, 139, 130]
# dark color in RGB = [82, 74, 71]
# How to convert these to HSV?
# using 150,0,0 here as it creates a valid range
hsv_color1 = np.array([150,0,0])

# using 180,255,255 here as it creates a valid range
hsv_color2 = np.array([180,255,255])
mask = cv2.inRange(img_hsv, hsv_color1, hsv_color2)
res = cv2.bitwise_and(img, img, mask = mask)
cv2.imshow('mask', mask)
cv2.imwrite("mask.jpg".format(latlon, zoom), mask)
cv2.imshow('img_hsv', img_hsv)
cv2.imwrite("img_hsv.jpg".format(latlon, zoom), img_hsv)
cv2.imshow('res', res)
cv2.imwrite("res.png".format(latlon, zoom), res)

So my 2 questions are:

  1. How to convert RGB to HSV values that will create a valid inRange to isolate these colours?
  2. How to only one area of inRange colour based on a given pixel position?
  3. And for a bonus point, how to make the mask for the isolated inRange area a nice tight mask?

I need to output an image that isolates the color area around a given pixel position.

Original ORIGINAL

Desired Output DESIRED OUTPUT

Light colour LIGHT COLOR

Dark colour DARK COLOR

Arkistarvh Kltzuonstev
  • 6,824
  • 7
  • 26
  • 56
user2115620
  • 101
  • 1
  • 10
  • Err, you didn't give us the *"given pixel position"*. – Mark Setchell Jul 31 '19 at 09:06
  • Sorry, my bad - for example x:235,y:343. I am also trying to detect the contours for each part on the roof. I have the following to get HSV values from an RGB colour: ```python start_r = 154 start_g = 141 start_b = 132 end_r = 82 end_g = 74 end_b = 71 start = np.uint8([[[start_b,start_g,start_r ]]]) hsv_start = cv2.cvtColor(start,cv2.COLOR_BGR2HSV)[0][0] end = np.uint8([[[end_b,end_g,end_r ]]]) hsv_end = cv2.cvtColor(end,cv2.COLOR_BGR2HSV)[0][0] print (hsv_start) print (hsv_end) ``` But I still get an empty mask ;( – user2115620 Jul 31 '19 at 09:29

1 Answers1

2

Your dark value becomes 16/13/32 in HSV. And your light value becomes 23/14/60 in HSV.

OpenCV scales the Hue values by dividing by 2 so that the full range of 360 becomes 180 and still fits into an unsigned 8-bit number. So, you need to use a dark Hue value of 8 and a light Hue value of 12. I would widen that range by 3-5 at each end to allow some leeway, and use a lowish saturation to only pick up unsaturated, greyish values. So the code becomes:

#!/usr/bin/env python3

import cv2
import numpy as np

img = cv2.imread("static.jpg")
img_hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)

# light color in RGB = [153, 139, 130]
# dark color in RGB = [82, 74, 71]

hsv_lo = np.array([5,0,0])
hsv_hi = np.array([15,50,255])
mask = cv2.inRange(img_hsv, hsv_lo, hsv_hi)
res = cv2.bitwise_and(img, img, mask = mask)
cv2.imwrite("result.png", res)

enter image description here

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