How can I remove the bright glare regions in image - python

I have some tomato images with bright shadow on tomatoes. I want to remove/reduce these bright shadow points. Is there any suggestion?
I tried below code but It did not solve my problem:
def decrease_brightness(img, value=30):
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
h, s, v = cv2.split(hsv)
lim = 255 - value
v[v >= lim] -= value
final_hsv = cv2.merge((h, s, v))
img = cv2.cvtColor(final_hsv, cv2.COLOR_HSV2BGR)
return img
image = decrease_brightness(image, value=50)

Here is how to do the inpainting in Python/OpenCV.
Note that shadows are dark. You want to remove the bright glare regions. Please use the correct terms so that you do not confuse others on the forum. Refer to a dictionary.
Read the input
Threshold on the gray background using cv2.inRange()
Apply morphology to close and dilate
Floodfill the outside with black to make a mask image
Use the mask to do the inpainting (two methods)
Save the results
Input:
import cv2
import numpy as np
# read image
img = cv2.imread('tomato.jpg')
hh, ww = img.shape[:2]
# threshold
lower = (150,150,150)
upper = (240,240,240)
thresh = cv2.inRange(img, lower, upper)
# apply morphology close and open to make mask
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (7,7))
morph = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel, iterations=1)
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (25,25))
morph = cv2.morphologyEx(morph, cv2.MORPH_DILATE, kernel, iterations=1)
# floodfill the outside with black
black = np.zeros([hh + 2, ww + 2], np.uint8)
mask = morph.copy()
mask = cv2.floodFill(mask, black, (0,0), 0, 0, 0, flags=8)[1]
# use mask with input to do inpainting
result1 = cv2.inpaint(img, mask, 101, cv2.INPAINT_TELEA)
result2 = cv2.inpaint(img, mask, 101, cv2.INPAINT_NS)
# write result to disk
cv2.imwrite("tomato_thresh.jpg", thresh)
cv2.imwrite("tomato_morph.jpg", morph)
cv2.imwrite("tomato_mask.jpg", mask)
cv2.imwrite("tomato_inpaint1.jpg", result1)
cv2.imwrite("tomato_inpaint2.jpg", result2)
# display it
cv2.imshow("IMAGE", img)
cv2.imshow("THRESH", thresh)
cv2.imshow("MORPH", morph)
cv2.imshow("MASK", mask)
cv2.imshow("RESULT1", result1)
cv2.imshow("RESULT2", result2)
cv2.waitKey(0)
Threshold Image:
Morphology and Floodfill Image:
Mask Image:
Inpaint Telea:
Inpaint Navier-Stokes:

Related

How can I get only the mask of an image?

Hi I am trying to get a mask of a T-shirt.
Here is what I am getting:
However, I would like to only receive the garment's shape without the print in the middle. How can I do that?
Thanks!
Here is the code:
import cv2
import numpy as np
# load image whose you want to create mask
img = cv2.imread('01430_00.jpg')
# convert to graky
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# threshold input image as mask
mask = cv2.threshold(gray,220,220, cv2.THRESH_BINARY)[1]
# negate mask
mask = 255 - mask
# apply morphology to remove isolated extraneous noise
# use borderconstant of black since foreground touches the edges
kernel = np.ones((3,3), np.uint8)
mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel)
mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel)
# anti-alias the mask -- blur then stretch
# blur alpha channel
mask = cv2.GaussianBlur(mask, (0,0), sigmaX=2, sigmaY=2, borderType =
cv2.BORDER_DEFAULT)
# linear stretch so that 127.5 goes to 0, but 255 stays 255
mask = (2*(mask.astype(np.float32))-255.0).clip(0,255).astype(np.uint8)
# Show Image in Opencv Windows
cv2.imshow("Original", img)
cv2.imshow("MASK", mask)
# Save mask Image
cv2.imwrite("Mask2.jpg",mask)
cv2.waitKey(0)
cv2.destroyAllWindows()
You already have a large contour for "garment". You can fill inside of the largest contour with the following code
contours, _ = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
cnt = max(contours, key = cv2.contourArea)
cv2.drawContours(mask,[cnt],0,255,-1)

Identify and count objects different from background

I try to use python, NumPy, and OpenCV to analyze the image below and just draw a circle on each object found. The idea here is not to identify the bug only identify any object that is different from the background.
Original Image:
Here is the code that I'm using.
import cv2
import numpy as np
img = cv2.imread('per.jpeg', cv2.IMREAD_GRAYSCALE)
if cv2.__version__.startswith('2.'):
detector = cv2.SimpleBlobDetector()
else:
detector = cv2.SimpleBlobDetector_create()
keypoints = detector.detect(img)
print(len(keypoints))
imgKeyPoints = cv2.drawKeypoints(img, keypoints, np.array([]), (0,0,255), cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
status = cv2.imwrite('teste.jpeg',imgKeyPoints)
print("Image written to file-system : ",status)
But the problem is that I'm getting only a greyscale image as result without any counting or red circle, as shown below:
Since I'm new to OpenCV and object recognition world I'm not able to identify what is wrong, and any help will be very appreciated.
Here is one way in Python/OpenCV.
Threshold on the bugs color in HSV colorspace. Then use morphology to clean up the threshold. Then get contours. Then find the minimum enclosing circle around each contour. Then bias the radius to make a bit larger and draw the circle around each bug.
Input:
import cv2
import numpy as np
# read image
img = cv2.imread('bugs.jpg')
# convert image to hsv colorspace
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# threshold on bugs color
lower=(0,90,10)
upper=(100,250,170)
thresh = cv2.inRange(hsv, lower, upper)
# apply morphology to clean up
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3,3))
morph = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel)
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (6,6))
morph = cv2.morphologyEx(morph, cv2.MORPH_CLOSE, kernel)
# get external contours
contours = cv2.findContours(morph, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours = contours[0] if len(contours) == 2 else contours[1]
result = img.copy()
bias = 10
for cntr in contours:
center, radius = cv2.minEnclosingCircle(cntr)
cx = int(round(center[0]))
cy = int(round(center[1]))
rr = int(round(radius)) + bias
cv2.circle(result, (cx,cy), rr, (0, 0, 255), 2)
# save results
cv2.imwrite('bugs_threshold.jpg', thresh)
cv2.imwrite('bugs_cleaned.jpg', morph)
cv2.imwrite('bugs_circled.jpg', result)
# display results
cv2.imshow('thresh', thresh)
cv2.imshow('morph', morph)
cv2.imshow('result', result)
cv2.waitKey(0)
cv2.destroyAllWindows()
Threshold Image:
Morphology Cleaned Image:
Resulting Circles:

How to remove text from color image by using python

I try to remove background and white text from a photo 1 like below but I can only remove like these images2 3. They still have white text inside the circle.
I've used the following code.
Any help from everyone is greatly appreciated by me.
img = cv2.imread('sample.jpg')
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
#Crop image
croped_img = img[51:403,102:454]
#plt.imshow(croped_img)
radius = 176
cx, cy = radius, radius # The center of circle
x,y = np.ogrid[-radius: radius, -radius: radius]
index = x**2 + y**2 > radius**2
croped_img[cy-radius:cy+radius, cx-radius:cx+radius][index] = 0
plt.imshow(croped_img)
croped_img=cv2.cvtColor(croped_img, cv2.COLOR_BGR2RGB)
cv2.imwrite('croped_circle_2.jpg', croped_img)
One approach is to create a mask of the text and use that to do inpainting. In Python/OpenCV, there are two forms of inpainting: Telea and Navier-Stokes. Both produce about the same results.
Input:
import cv2
import numpy as np
# read input
img = cv2.imread('circle_text.png')
# convert to gray
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# threshold and invert
thresh = cv2.threshold(gray, 155, 255, cv2.THRESH_BINARY)[1]
# apply morphology close
kernel = np.ones((3,3), np.uint8)
thresh = cv2.morphologyEx(thresh, cv2.MORPH_DILATE, kernel)
# get contours and filter to keep only small regions
mask = np.zeros_like(gray, dtype=np.uint8)
cntrs = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cntrs = cntrs[0] if len(cntrs) == 2 else cntrs[1]
for c in cntrs:
area = cv2.contourArea(c)
if area < 1000:
cv2.drawContours(mask,[c],0,255,-1)
# do inpainting
result1 = cv2.inpaint(img,mask,3,cv2.INPAINT_TELEA)
result2 = cv2.inpaint(img,mask,3,cv2.INPAINT_NS)
# save results
cv2.imwrite('circle_text_threshold.png', thresh)
cv2.imwrite('circle_text_mask.png', mask)
cv2.imwrite('circle_text_inpainted_telea.png', result1)
cv2.imwrite('circle_text_inpainted_ns.png', result2)
# show results
cv2.imshow('thresh',thresh)
cv2.imshow('mask',mask)
cv2.imshow('result1',result1)
cv2.imshow('result2',result2)
cv2.waitKey(0)
cv2.destroyAllWindows()
Threshold image:
Mask image:
Telea Inpainting:
Navier-Stokes Inpainting:

Removing White Text with Black Borders From Image

I am trying to remove text from images that has a black border with white fill. Take the image below as an example.
I have tried a few options utilizing opencv and skimage inpaint
import cv2
from skimage.restoration import inpaint
img = cv2.imread('Documents/test_image.png')
mask = cv2.threshold(img, 210, 255, cv2.THRESH_BINARY)[1][:,:,0]
dst = cv2.inpaint(img, mask, 7, cv2.INPAINT_TELEA)
image_result = inpaint.inpaint_biharmonic(img, mask,
multichannel=True)
cv2.imshow('image',img)
cv2.imshow('mask',mask)
cv2.imshow('dst',dst)
cv2.imshow('image_result',image_result)
cv2.waitKey(0)
It seems like the inpainting is just trying to fill with black as that is what it is identifying as being around the areas of interest. What I would like to do is remove the white text and black borders completely, or secondarily try to fill the white with more information from surrounding colors than just the black.
Here is the best solution I could come up with, still open to others with more experience showing me a better way if anyone has an idea.
mask = cv2.threshold(img, 245, 255, cv2.THRESH_BINARY)[1][:,:,0]
new_mask = cv2.dilate(mask, cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (10,10)))
dst = cv2.inpaint(img, new_mask, 7, cv2.INPAINT_TELEA)
Here are two inpainting methods in Python/OpenCV. Note that I use the saturation channel to create the threshold, since white and black have zero saturation, in principle.
Input:
import cv2
import numpy as np
# read input
img = cv2.imread('white_black_text.png')
# convert to hsv and extract saturation
hsv = cv2.cvtColor(img,cv2.COLOR_BGR2HSV)
sat = hsv[:,:,1]
# threshold and invert
thresh = cv2.threshold(sat, 10, 255, cv2.THRESH_BINARY)[1]
thresh = 255 - thresh
# apply morphology dilate
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (15,15))
thresh = cv2.morphologyEx(thresh, cv2.MORPH_DILATE, kernel)
# do inpainting
result1 = cv2.inpaint(img,thresh,11,cv2.INPAINT_TELEA)
result2 = cv2.inpaint(img,thresh,11,cv2.INPAINT_NS)
# save results
cv2.imwrite('white_black_text_threshold.png', thresh)
cv2.imwrite('white_black_text_inpainted1.png', result1)
cv2.imwrite('white_black_text_inpainted2.png', result1)
# show results
cv2.imshow('thresh',thresh)
cv2.imshow('result1',result1)
cv2.imshow('result2',result2)
cv2.waitKey(0)
cv2.destroyAllWindows()
Threshold and morphology cleaned result:
Result 1 (Telea):
Result 2 (Navier Stokes):

How to remove glare from images in opencv?

This mathematica code removes glare from an image:
img = Import["foo.png"]
Inpaint[img, Dilation[saturated, DiskMatrix[20]]]
as shown in the most upvoted answer here:
https://dsp.stackexchange.com/questions/1215/how-to-remove-a-glare-clipped-brightness-from-an-image
I want to use opencv instead of Mathematica to get the same result. How would I write equivalent code in opencv-python?
Here is how to do that in Python/OpenCV.
But I do not think the OpenCV inpainting routines are working or at least are not working well for my Python 3.7.5 and OpenCV 3.4.8.
Input:
import cv2
import numpy as np
# read image
img = cv2.imread('apple.png')
# convert to gray
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# threshold grayscale image to extract glare
mask = cv2.threshold(gray, 220, 255, cv2.THRESH_BINARY)[1]
# Optionally add some morphology close and open, if desired
#kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (7,7))
#mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel, iterations=1)
#kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3,3))
#mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel, iterations=1)
# use mask with input to do inpainting
result = cv2.inpaint(img, mask, 21, cv2.INPAINT_TELEA)
# write result to disk
cv2.imwrite("apple_mask.png", mask)
cv2.imwrite("apple_inpaint.png", result)
# display it
cv2.imshow("IMAGE", img)
cv2.imshow("GRAY", gray)
cv2.imshow("MASK", mask)
cv2.imshow("RESULT", result)
cv2.waitKey(0)
Thresholded image:
Result:

Categories

Resources