How to crop image based on the object radius using OpenCV? - python

I'm new to python. I know basics about image-preprocessing. I don't know how to remove background and crop an image using OpenCV.

Here is the processing in Python/OpenCV for your new image.
Input:
import cv2
import numpy as np
# load image as grayscale
img = cv2.imread('Diabetic-Retinopathy_G_RM_151064169.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# threshold input image
mask = cv2.threshold(gray, 10, 255, cv2.THRESH_BINARY)[1]
# optional morphology to clean up small spots
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3,3))
mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel)
mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel)
# put mask into alpha channel of image
result = np.dstack((img, mask))
# save resulting masked image
cv2.imwrite('Diabetic-Retinopathy_G_RM_151064169_masked.png', result)
# display result, though it won't show transparency
cv2.imshow("mask", mask)
cv2.imshow("RESULT", result)
cv2.waitKey(0)
cv2.destroyAllWindows()
Result

Here is one way to do that in Python/OpenCV.
Read input
Convert to grayscale
Threshold and invert as mask
Put mask into alpha channel of input
Save result
Input:
import cv2
import numpy as np
# load image
img = cv2.imread('black_circle.png')
# convert to grayscale
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# threshold
threshold = cv2.threshold(gray,128,255,cv2.THRESH_BINARY)[1]
# invert so circle is white on black
mask = 255 - threshold
# put mask into alpha channel of image
result = np.dstack((img, mask))
# save resulting masked image
cv2.imwrite('black_circle_masked.png', result)
# display result, though it won't show transparency
cv2.imshow("MASK", mask)
cv2.imshow("RESULT", result)
cv2.waitKey(0)
cv2.destroyAllWindows()
Result:
Note: download the result to see the transparency.

Related

Remove letter artifacts from mammography image

I want to remove the letter artifacts "L:CC and Strin" from breast mammography using python. How could I get that done? this is my image
Here is one way to do that in Python/OpenCV.
Read the input
Convert to grayscale
Threshold
Dilate as mask
Apply mask to change white letters to black
Save the results
import cv2
import numpy as np
# read image
img = cv2.imread('mammogram_letters.png')
# convert to gray
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# create mask
thresh = cv2.threshold(gray, 247, 255, cv2.THRESH_BINARY)[1]
# dilate mask
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))
mask = cv2.morphologyEx(thresh, cv2.MORPH_DILATE, kernel)
# apply change
result = img.copy()
result[mask == 255] = (0,0,0)
# save result
cv2.imwrite("mammogram_letters_thresh.png", thresh)
cv2.imwrite("mammogram_letters_mask.png", mask)
cv2.imwrite("mammogram_letters_blackened.png", result)
# show results
cv2.imshow("THRESH", thresh)
cv2.imshow("MASK", mask)
cv2.imshow("RESULT", result)
cv2.waitKey(0)
Threshold image:
Mask image:
Result:
You have to get pixel coordinate of the box containing test, if they are always the same my code will work.
from PIL import Image
im = Image.open('SqbIx.png')
img =im.load()
for i in range (73,116):
for j in range (36,57):
img[i,j]= (0, 0, 0)
im.save('mod.png')

OpenCV Python how to keep one color as is converting an image to Grayscale

How do I make it so everything in the image is in gray-scale except the orange cone. Using opencv python.
You can achieve your goal by using bitwise_and() function and thresholding.
Steps:
generate mask for the required region.(here thresholding is used but other methods can also be used)
extract required regions using bitwise_and (image & mask).
Add masked regions to get output.
Here's sample code:
import cv2
import numpy as np
img = cv2.imread('input.jpg')
# creating mask using thresholding over `red` channel (use better use histogram to get threshoding value)
# I have used 200 as thershoding value it can be different for different images
ret, mask = cv2.threshold(img[:, :,2], 200, 255, cv2.THRESH_BINARY)
mask3 = np.zeros_like(img)
mask3[:, :, 0] = mask
mask3[:, :, 1] = mask
mask3[:, :, 2] = mask
# extracting `orange` region using `biteise_and`
orange = cv2.bitwise_and(img, mask3)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
img = cv2.cvtColor(gray, cv2.COLOR_GRAY2BGR)
# extracting non-orange region
gray = cv2.bitwise_and(img, 255 - mask3)
# orange masked output
out = gray + orange
cv2.imwrite('orange.png', orange)
cv2.imwrite('gray.png', gray)
cv2.imwrite("output.png", out)
Results:
masked orange image
masked gray image
output image
Here is an alternate way to do that in Python/OpenCV.
Read the input
Threshold on color using cv2.inRange()
Apply morphology to clean it up and fill in holes as a mask
Create a grayscale version of the input
Merge the input and grayscale versions using the mask via np.where()
Save the results
Input:
import cv2
import numpy as np
img = cv2.imread("orange_cone.jpg")
# threshold on orange
lower = (0,60,200)
upper = (110,160,255)
thresh = cv2.inRange(img, lower, upper)
# apply morphology and make 3 channels as mask
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5,5))
mask = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)
mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel)
mask = cv2.merge([mask,mask,mask])
# create 3-channel grayscale version
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
gray = cv2.cvtColor(gray, cv2.COLOR_GRAY2BGR)
# blend img with gray using mask
result = np.where(mask==255, img, gray)
# save images
cv2.imwrite('orange_cone_thresh.jpg', thresh)
cv2.imwrite('orange_cone_mask.jpg', mask)
cv2.imwrite('orange_cone_result.jpg', result)
# Display images
cv2.imshow("thresh", thresh)
cv2.imshow("mask", mask)
cv2.imshow("result", result)
cv2.waitKey(0)
Threshold image:
Mask image:
Merged result:

how to remove background of images in python

I have a dataset that contains full width human images I want to remove all the backgrounds in those Images and just leave the full width person,
my questions:
is there any python code that does that ?
and do I need to specify each time the coordinate of the person object?
Here is one way using Python/OpenCV.
Read the input
Convert to gray
Threshold and invert as a mask
Optionally apply morphology to clean up any extraneous spots
Anti-alias the edges
Convert a copy of the input to BGRA and insert the mask as the alpha channel
Save the results
Input:
import cv2
import numpy as np
# load image
img = cv2.imread('person.png')
# convert to graky
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# threshold input image as mask
mask = cv2.threshold(gray, 250, 255, 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)
# put mask into alpha channel
result = img.copy()
result = cv2.cvtColor(result, cv2.COLOR_BGR2BGRA)
result[:, :, 3] = mask
# save resulting masked image
cv2.imwrite('person_transp_bckgrnd.png', result)
# display result, though it won't show transparency
cv2.imshow("INPUT", img)
cv2.imshow("GRAY", gray)
cv2.imshow("MASK", mask)
cv2.imshow("RESULT", result)
cv2.waitKey(0)
cv2.destroyAllWindows()
Transparent result:

How can I replace `plt.imsave` with `cmap` option set to `gray` with opencv operations?

This is the source image I am working with:
I am using this github repository (the file I'm using is tools/test_lanenet.py) to do binary lane segmentation. now I get this image:
The second image is actually an image resulted from this command:
# this line results in an array with the shape of (512, 256). this is just a hypothetical line of code. what I really care is the line which saves the image with matplotlib library.
binary_seg_image = lane_segmenter.binary_segment()
# this line saves the image
plt.imsave('binary_image_plt.png', binary_seg_image[0] * 255, cmap='gray')
First I have to do the same operation with opencv module and preferably faster.
In next operation I have to map the lanes segmented in second image on the source image road lanes. I think I have to use the second image as mask and use cv2.bitwise_andto do job right? Can anybody help me?
thank you guys
If you want to color the image where the mask exists, then this is one way using Python/OpenCV. In place of bitwise_and, you simply have to do numpy coloring where the mask is white. Note again, your images are not the same size and I do not know how best to align them. I leave that to you. I am using your two input images as in my other answer. The code is nearly the same.
import cv2
import numpy as np
# read image
img = cv2.imread('road.png')
ht, wd, cc = img.shape
print(img.shape)
# read mask as grayscale
gray = cv2.imread('road_mask.png', cv2.IMREAD_GRAYSCALE)
hh, ww = gray.shape
print(gray.shape)
# get minimum dimensions
hm = min(ht, hh)
wm = min(wd, ww)
print(hm, wm)
# crop img and gray to min dimensions
img = img[0:hm, 0:wm]
gray = gray[0:hm, 0:wm]
# threshold gray as mask
thresh = cv2.threshold(gray,128,255,cv2.THRESH_BINARY)[1]
print(thresh.shape)
# apply mask to color image
result = img.copy()
result[thresh==255] = (0,0,255)
cv2.imshow('image', img)
cv2.imshow('gray', gray)
cv2.imshow('thresh', thresh)
cv2.imshow('result', result)
cv2.waitKey(0)
cv2.destroyAllWindows()
# save results
cv2.imwrite('road_colored_by_mask.png', result)
Your images are not the same size. To mask the black/white image onto the color image, they need to align. I tried to simply crop them to the same minimum dimensions at the top left corner, but that did not align them properly.
However, this Python/OpenCV code will give you some idea how to start once you figure out how to align them.
Color Input:
B/W Lane Image:
import cv2
import numpy as np
# read image
img = cv2.imread('road.png')
ht, wd, cc = img.shape
print(img.shape)
# read mask as grayscale
gray = cv2.imread('road_mask.png', cv2.IMREAD_GRAYSCALE)
hh, ww = gray.shape
print(gray.shape)
# get minimum dimensions
hm = min(ht, hh)
wm = min(wd, ww)
print(hm, wm)
# crop img and gray to min dimensions
img = img[0:hm, 0:wm]
gray = gray[0:hm, 0:wm]
# threshold gray as mask
thresh = cv2.threshold(gray,128,255,cv2.THRESH_BINARY)[1]
print(thresh.shape)
# make thresh 3 channels as mask
mask = cv2.merge((thresh, thresh, thresh))
# apply mask to color image
result = cv2.bitwise_and(img, mask)
cv2.imshow('image', img)
cv2.imshow('gray', gray)
cv2.imshow('thresh', thresh)
cv2.imshow('mask', mask)
cv2.imshow('masked image', result)
cv2.waitKey(0)
cv2.destroyAllWindows()
# save results
cv2.imwrite('road_masked_on_black.png', result)

How to discard the edges of an image using opencv?

I'm pre-processing some images in order to remove the background from my area of ​​interest. However, the images on my bench have rounded edges due to the focus of the camera. How do I discard these rounded edges and be able to remove only my object of interest from the image? The code below I can remove the background of the image, but it does not work right due to the edges around.
import numpy as np
import cv2
#Read the image and perform threshold and get its height and weight
img = cv2.imread('IMD408.bmp')
h, w = img.shape[:2]
# Transform to gray colorspace and blur the image.
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray,(5,5),0)
# Make a fake rectangle arround the image that will seperate the main contour.
cv2.rectangle(blur, (0,0), (w,h), (255,255,255), 10)
# Perform Otsu threshold.
_,thresh = cv2.threshold(blur,0,255,cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)
# Create a mask for bitwise operation
mask = np.zeros((h, w), np.uint8)
# Search for contours and iterate over contours. Make threshold for size to
# eliminate others.
contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
for i in contours:
cnt = cv2.contourArea(i)
if 1000000 >cnt > 100000:
cv2.drawContours(mask, [i],-1, 255, -1)
# Perform the bitwise operation.
res = cv2.bitwise_and(img, img, mask=mask)
# Display the result.
cv2.imwrite('IMD408.png', res)
cv2.imshow('img', res)
cv2.waitKey(0)
cv2.destroyAllWindows()
input image:
Exit:
Error:
Since you mentioned that all the images have the same hue, then this should work well for them. Steps is to do some white balancing which will increase the contrast a bit.
Get the greyscale.
Threshold the grayscale image. Values less than 127 are set to 255 (white). This will give you a binary image, which will become a mask for the original image.
Apply the mask
You might have to play around with the thresholding if you want better results, here is the link for that. But this should get you started. I'm using a different OpenCV version compared to you might have to tweak the code a bit.
import cv2
def equaliseWhiteBalance(image):
''' Return equilised WB of an image '''
wb = cv2.xphoto.createSimpleWB() #Create WB Object
imgWB = wb.balanceWhite(img) #Balance White on image
r,g,b = cv2.split(imgWB) #Get individual r,g,b channels
r_equ = cv2.equalizeHist(r) #Equalise RED channel
g_equ = cv2.equalizeHist(g) #Equalise GREEN channel
b_equ = cv2.equalizeHist(b) #Equalise BLUE channel
img_equ_WB = cv2.merge([r_equ,g_equ,b_equ]) #Merge equalised channels
return imgWB
#Read the image
img = cv2.imread('IMD408.bmp')
result = img.copy()
#Get whiteBalance of image
imgWB = equaliseWhiteBalance(img)
cv2.imshow('img', imgWB)
cv2.waitKey(0)
# Get gray image
gray = cv2.cvtColor(imgWB,cv2.COLOR_RGB2GRAY)
cv2.imshow('img', gray)
cv2.waitKey(0)
# Perform threshold
_, thresh = cv2.threshold(gray,127,255,cv2.THRESH_BINARY)
cv2.imshow('img', thresh)
cv2.waitKey(0)
# Apply mask
result[thresh!=0] = (255,255,255)
cv2.imshow('img', result)
cv2.waitKey(0)
If all the dark corner vignettes have different sizes per image, then I suggest looking for centroid of contours on the binary (mask) image. Centroids with a 'short' distance to any corner of your image will be the dark vignettes, so their value can be changed from black to white.

Categories