I may be overshooting a bit but I'm trying to use a mask generated from my image and subtract it from the main image. I'm quite open to instead extracting the characters but am not sure how to collect the entire blue sample, I haven't that correct balance yet.
The page here demonstrates the inverse of what I'm trying to achieve.
Base image
The mask utilizing hsv bounds then inverting it to show it better
Darkening it
I wish to now take that mask and remove it from the main image.
import cv2
import numpy as np
import random as rng
from PIL import Image
from PIL import ImageOps
from utils import helper
image_name = 'capt13.jpg'
img = cv2.imread(image_name)
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
lower_red = np.array([0,120,70])
upper_red = np.array([10,255,255])
lower_mask = cv2.inRange(hsv, lower_red, upper_red)
lower_red = np.array([160,120,70])
upper_red = np.array([180,255,255])
upper_mask = cv2.inRange(hsv, lower_red, upper_red)
'''
lower_blue = np.array([80,40,30])
upper_blue = np.array([140,255,255])
lower_mask = cv2.inRange(hsv, lower_blue, upper_blue)
lower_blue = np.array([240,220,200])
upper_blue = np.array([360,255,255])
upper_mask = cv2.inRange(hsv, lower_blue, upper_blue)
'''
mask = lower_mask + upper_mask
res_lines = cv2.bitwise_and(img,img, mask= mask)
# Keep the inverted
image = Image.fromarray(res_lines)
image.save('res.png')
inverted = ImageOps.invert(image)
inverted = inverted.convert('L')
inverted.save('inverted.png')
binary = np.array(inverted)
for row in range(len(binary)):
for col in range(len(binary[row])):
if binary[row][col] != 255:
binary[row][col] = 0
binary_image = Image.fromarray(binary)
binary_image.save('binary.png')
Extracting the Blue (As stated above that I'm open to a better solution for this)
The mask utilizing hsv bounds then inverted it
Darkening it
Straight subtraction works, provided both images are the same size:
im = cv2.imread("image.png")
mask = cv2.imread("mask.png")
diff_im = im - im2
Alternatively, you can use OpenCV's built in subtract, which does an element-wise subtraction:
diff_im = cv2.subtract(im, im2)
As a final thought, you should also try absdiff, as it will convert negative results to zeroes, which may be what you want.
diff_im = cv2.absdiff(im, im2)
Related
How do ı make the image I've masked smoother? I want to remove the little white pixels from the second picture, and I want to throw some of the masked places out of the picture, how can I do that?
import cv2
import numpy as np
img = cv2.imread("colors.jpg")
height,width = 720,720
img = cv2.resize(img,(width,height))
hsv = cv2.cvtColor(img,cv2.COLOR_BGR2HSV)
lower_range = np.array([100,50,50])
upper_range = np.array([150,255,255])
mask = cv2.inRange(hsv, lower_range, upper_range)
#res = cv2.bitwise_and(img,img, mask=mask)
cv2.imshow("Image",img)
cv2.imshow("Mask",mask)
#cv2.imshow("res",res)
cv2.waitKey(0)
cv2.destroyAllWindows
Try using the closing and opening concept of computer vision. You need is erosion in your case to get rid of the tiny white dots.
There are two things that can controlled for the resultant outcome as per your requirement i.e. kernel size and iterations.
Here is the code is I could reproduce and provide a near solution.
import numpy as np
img = cv2.imread("colors.jpg")
height,width = 720,720
img = cv2.resize(img,(width,height))
hsv = cv2.cvtColor(img,cv2.COLOR_BGR2HSV)
lower_range = np.array([100,50,50])
upper_range = np.array([150,255,255])
kernel = np.ones((5,5),np.uint8)
mask = cv2.inRange(hsv, lower_range, upper_range)
erosion = cv2.erode(mask,kernel,iterations = 1)
#res = cv2.bitwise_and(img,img, mask=mask)
cv2.imshow("Image",img)
cv2.imshow("Mask",erosion)
#cv2.imshow("res",res)
cv2.waitKey(0)
cv2.destroyAllWindows
import cv2
import numpy as np
img = cv2.imread("colors.jpg")
height,width = 720,720
img = cv2.resize(img,(width,height))
hsv = cv2.cvtColor(img,cv2.COLOR_BGR2HSV)
lower_range = np.array([100,50,50])
upper_range = np.array([150,255,255])
kernel = np.ones((5,5),np.uint8)
mask = cv2.inRange(hsv, lower_range, upper_range)
erosion = cv2.erode(mask,kernel,iterations = 1)
#res = cv2.bitwise_and(img,img, mask=mask)
cv2.imshow("Image",img)
cv2.imshow("Mask",erosion)
#cv2.imshow("res",res)
cv2.waitKey(0)
cv2.destroyAllWindows
Result:
I have below preprocessed rice image. I want to fill the rice with black color and then perform the inverse operation to find contours. I am trying to use Erosion/Dilation operation but not working. Below is the code snippet I am using.
First I used shadow removal algorithm then used adaptive thresholding which gives the Input image. Now, I want to change the Input image to the output image.
Original Image:
Input Image:
Required Output Image:
Code Snippet:
oposite = cv2.bitwise_not(img)
#Erosion
kernel = np.ones((3,3),np.uint8)
erosion = cv2.dilate(des,kernel,iterations = 1)
erosion = cv2.bitwise_not(erosion)
im_out = oposite + erosion
cv2.imshow("output", im_out)
cv2.waitKey(0)
You can create an HSV mask by using the cv2.COLOR_BGR2HSV flag in the cv2.cvtColor() method, and by using the cv2.inRange() method. I basically changed the maximum saturation value from 255 to 100:
import cv2
import numpy as np
img = cv2.imread("rice.jpg")
img_hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
lower = np.array([0, 0, 0])
upper = np.array([179, 100, 255])
mask = cv2.inRange(img_hsv, lower, upper)
cv2.imshow("Mask", mask)
cv2.waitKey(0)
Output:
If you're looking to make the grains thinner, you can turn down the maximum hue value, from 179 to, say,111, along with the maximum saturation value at 100:
import cv2
import numpy as np
img = cv2.imread("rice.jpg")
img_hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
lower = np.array([0, 0, 0])
upper = np.array([111, 100, 255])
mask = cv2.inRange(img_hsv, lower, upper)
cv2.imshow("Mask", mask)
cv2.waitKey(0)
Output:
I tried a code from stackoverflow but it shows black color for me. what I want to do is:
Get Tomatoes white and other things black of this image
To get red colors out of this image I used this code:
import cv2
import numpy as np
img = cv2.imread('test.png')
img = np.copy(img)
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
lower_red = np.array([217, 25, 0])
upper_red = np.array([254, 217, 196])
mask = cv2.inRange(hsv, lower_red, upper_red)
#mask = cv2.bitwise_not(mask)
cv2.imwrite('mask.png', mask)
cv2.destroyAllWindows()
result is this
thank you for reading
The following adaptation from your code:
import cv2
import numpy as np
img = cv2.imread('test2.png')
img = np.copy(img)
rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
lower_red = np.array([225, 0, 0])
upper_red = np.array([255, 200, 200])
mask = cv2.inRange(rgb, lower_red, upper_red)
cv2.imwrite('mask.png', mask)
cv2.destroyAllWindows()
produces this output:
I simply removed the conversion to HSV (which is not necessary and I guess your initial lower and upper limits where thought to be for RGB anyway?). I played around a bit with the limits, but I guess, if you tinker a bit more with them, you can get better results.
Try this HSV mask:
import cv2
import numpy as np
img = cv2.imread("tomato.jpg")
lower = np.array([0, 55, 227])
upper = np.array([21, 255, 255])
mask = cv2.inRange(cv2.cvtColor(img, cv2.COLOR_BGR2HSV), lower, upper)
cv2.imshow("Image", mask)
cv2.waitKey(0)
Output:
I currently have the following code, it searches for a range of colors (blue) and is replacing it with a specific color, however, I would like to replace it with the closest color in the image, not the closest in the palette but in the image.
How can I do this?
import cv2
import numpy as np
import matplotlib.pyplot as plt
image = cv2.imread('test5.jpeg')
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
lower_blue = np.array([80,50,50], dtype="uint8")
upper_blue = np.array([101,255,255], dtype="uint8")
mask = cv2.inRange(hsv, lower_blue, upper_blue)
#image[mask > 0] = (183, 213, 247)
plt.figure()
plt.imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
mask = cv2.inRange(hsv, lower_blue, upper_blue)
mask = cv2.bitwise_and(image, image, mask=mask)
gray_mask = cv2.cvtColor(mask, cv2.COLOR_BGR2GRAY)
image = cv2.inpaint(image, gray_mask, 100, flags=cv2.INPAINT_TELEA)
I could solve my problem using the inpaint method.
https://www.pyimagesearch.com/2020/05/18/image-inpainting-with-opencv-and-python/
I was reading on how to filter colors using OpenCV and came across the following snippet.
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
lower_red = np.array([0,160,50])
upper_red = np.array([255,255,180])
mask = cv2.inRange(hsv, lower_red, upper_red)
res = cv2.bitwise_and(img,img, mask= mask)
What does each value in lower_red mean? Does it denote lower and upper limits of H,S,V sequentially? Should it be read as minimum value of H as 0 and maximum value of H as 255?
I want to filter red color.
You are well on your way. I've added some code that shows a solution to your problem - combining two HSV color ranges in one mask.
Result:
Code:
import numpy as np
import cv2
# load image
img = cv2.imread("HSV.JPG")
# convert to hsv
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# Create first mask
lower_red = np.array([0,150,50])
upper_red = np.array([5,255,255])
# Threshold the HSV image to get only green colors
mask = cv2.inRange(hsv, lower_red, upper_red)
# apply mask to original image
res = cv2.bitwise_and(img,img, mask= mask)
#show image
cv2.imshow("Mask1", res)
# Create second mask
lower_red2 = np.array([175,150,50])
upper_red2 = np.array([179,255,255])
# Threshold the HSV image to get only green colors
mask2 = cv2.inRange(hsv, lower_red2, upper_red2)
# apply mask to original image
res2 = cv2.bitwise_and(img,img, mask= mask2)
#show image
cv2.imshow("Mask2", res2)
#combine masks
final_mask = cv2.bitwise_or(mask, mask2)
# apply mask to original image
result = cv2.bitwise_and(img,img, mask= final_mask)
#show image
cv2.imshow("Result", result)
cv2.imshow("Image", img)
cv2.waitKey(0)
cv2.destroyAllWindows()
Note: in the result image I show the results if the separate masks were applied to the original image. Of course you really only need the masks, which are black and white.