LaVOZs

The World’s Largest Online Community for Developers

'; Changing colours of an area in an image using opencv in python - LavOzs.Com

I have a picture were I want to change all white-ish pixels to grey, but only for a certain area of the image. Example picture, I just want to change the picture outside of the red rectangle, without changing the image within the red rectangle

I already have the general code, which was part of someone elses Stackoverflow question, that changes the colour of every white pixel instead of only just the one outside of an area.

image = cv.imread("meme 2.jpg")
hsv = cv.cvtColor(image, cv.COLOR_BGR2HSV)

# Define lower and uppper limits of what we call "white-ish"
sensitivity = 19
lower_white = np.array([0, 0, 255 - sensitivity])
upper_white = np.array([255, sensitivity, 255])

# Mask image to only select white
mask = cv.inRange(hsv, lower_white, upper_white)

# Change image to grey where we found brown
image[mask > 0] = (170, 170, 170)
cv.imwrite(file, image)

Thanks for the help! let me know if something is unclear. best wishes, Paul

Here is one way to do that in Python/OpenCV.

  • Read the input
  • Convert to HSV color space
  • Threshold on desired color to make a mask
  • Use the mask to change the color of all corresponding pixels in the image
  • Draw a new rectangular mask for the region where you do not want to change
  • Invert the new mask for the region where you do want to change
  • Apply the new mask to the original image
  • Apply the inverted new mask to the color changed image
  • Add the two results together to form the final image
  • Save the results


Input:

enter image description here

import cv2
import numpy as np

# Read image
image = cv2.imread('4animals.jpg')

# Convert to HSV
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)

# Define lower and uppper limits of what we call "white-ish"
sensitivity = 19
lower_white = np.array([0, 0, 255 - sensitivity])
upper_white = np.array([255, sensitivity, 255])

# Create mask to only select white
mask = cv2.inRange(hsv, lower_white, upper_white)

# Change image to grey where we found white
image2 = image.copy()
image2[mask > 0] = (170, 170, 170)

# Create new rectangular mask that is white on black background
x,y,w,h = 33,100,430,550
mask2 = np.zeros_like(image)
cv2.rectangle(mask2, (x,y), (x+w,y+h), (255, 255, 255), -1)

# invert mask
mask2_inv = 255 - mask2

# apply mask to image
image_masked = cv2.bitwise_and(image, mask2)

# apply inverted mask to image2
image2_masked = cv2.bitwise_and(image2, mask2_inv)

# add together
result = cv2.add(image_masked, image2_masked)

# save results
cv2.imwrite('4animals_mask.jpg', mask)
cv2.imwrite('4animals_modified.png', image2)
cv2.imwrite('4animals_mask2.jpg', mask2)
cv2.imwrite('4animals_mask2_inv.jpg', mask2_inv)
cv2.imwrite('4animals_masked.jpg', image_masked)
cv2.imwrite('4animals_modified_masked.jpg', image2_masked)
cv2.imwrite('4animals_result.jpg', result)

cv2.imshow('mask', mask)
cv2.imshow('image2', image2)
cv2.imshow('mask2', mask2 )
cv2.imshow('mask2_inv', mask2_inv)
cv2.imshow('image_masked', image_masked)
cv2.imshow('image2_masked', image2_masked)
cv2.imshow('result', result)
cv2.waitKey(0)
cv2.destroyAllWindows()


Color mask:

enter image description here

Rectangle mask:

enter image description here

Inverted rectangle mask:

enter image description here

Color changed image:

enter image description here

Masked input:

enter image description here

Masked color changed image:

enter image description here

Result:

enter image description here

Here is another simpler method in Python/OpenCV. My previous answer was overly complicated.

  • Read the input
  • Convert to HSV color space
  • Create a mask image by color thresholding
  • Draw a black rectangle on the previous mask for where you do not want to change the color
  • Apply the new combined mask to the image to change the color in the desired region
  • Save the result


Input:

enter image description here

import cv2
import numpy as np

# Read image
image = cv2.imread('4animals.jpg')

# Convert to HSV
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)

# Define lower and uppper limits of what we call "white-ish"
sensitivity = 19
lower_white = np.array([0, 0, 255 - sensitivity])
upper_white = np.array([255, sensitivity, 255])

# Create mask to only select white
mask = cv2.inRange(hsv, lower_white, upper_white)

# Draw new rectangular mask on old mask that is black inside the rectangle and white outside the rectangle
x,y,w,h = 33,100,430,550
mask2 = mask.copy()
cv2.rectangle(mask2, (x,y), (x+w,y+h), 0, -1)

# Change image to grey where we found white for combined mask
result = image.copy()
result[mask2 > 0] = (170, 170, 170)

# save results
cv2.imwrite('4animals_mask.jpg', mask)
cv2.imwrite('4animals_mask2.jpg', mask2)
cv2.imwrite('4animals_result.jpg', result)

cv2.imshow('mask', mask)
cv2.imshow('mask2', mask2 )
cv2.imshow('result', result)
cv2.waitKey(0)
cv2.destroyAllWindows()


Mask from color thresholding:

enter image description here

Modified mask with rectangle drawn over it:

enter image description here

Result:

enter image description here

Related
How do I merge two dictionaries in a single expression in Python?
Calling an external command from Python
What are metaclasses in Python?
Does Python have a ternary conditional operator?
How to get the current time in Python
How to lazy load images in ListView in Android
Manually raising (throwing) an exception in Python
Does Python have a string 'contains' substring method?
Image Processing: Algorithm Improvement for 'Coca-Cola Can' Recognition