How to remove background using Canny Edge detection - python

I want to remove background and sharpen the images of following type:
image 1
Both of these are signatures. I want to be able to remove everything except the signature itself and sharpen the lines of signature.
I am able to get a mask using Canny edge detection using following code
import cv2
im_path = r'test2.png'
image = cv2.imread(im_path) #args["image"]
image = cv2.resize(image, (680, 460))
#rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]
cv2.imshow('thresh', thresh) ###for showing
cv2.imwrite('thresh.jpg', thresh) ###for saving
cv2.waitKey()
And these are masks I get;
But Im clueless about what Image processing operations to perform next.
PS: These signatures are same (not forged) and next step would be to find similarity between them.

Try this
import cv2
import numpy as np
image = cv2.imread("r'test2.png'")
original = image.copy()
mask = np.zeros(image.shape, dtype=np.uint8)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5,5))
opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations=3)
cnts = cv2.findContours(opening, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
cnts = sorted(cnts, key=cv2.contourArea, reverse=True)
for c in cnts:
cv2.drawContours(mask, [c], -1, (255,255,255), -1)
break
close = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel, iterations=4)
close = cv2.cvtColor(close, cv2.COLOR_BGR2GRAY)
result = cv2.bitwise_and(original, original, mask=close)
result[close==0] = (255,255,255)
cv2.imshow('result', result)
cv2.waitKey()

Related

How to split an image using edge detection in python

My images are stored in an numpy array I want to split the images into individual images containing single character.
import cv2
# Load image, grayscale, Gaussian blur, Otsu's threshold, dilate
image = arr #numpy_arr_containing 200X200 image
original = image.copy()
gray = image
blur = cv2.GaussianBlur(gray, (5,5), 0)
thresh = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (15,15))
dilate = cv2.dilate(thresh, kernel, iterations=2)
# Find contours, obtain bounding box coordinates, and extract ROI
cnts = cv2.findContours(dilate, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
image_number = 0
for c in cnts:
x,y,w,h = cv2.boundingRect(c)
cv2.rectangle(image, (x, y), (x + w, y + h), (36,255,12), 3)
ROI = original[y:y+h, x:x+w]
cv2.imwrite("ROI_{}.png".format(image_number), ROI)
image_number += 1
# cv2.imshow('image', image)
# cv2.imshow('thresh', thresh)
# cv2.imshow('dilate', dilate)
# cv2.waitKey()

How to extract only brain part in center in MRI image? [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 1 year ago.
Improve this question
I have a MRI image of brain. I need to remove cranium (skull) from MRI and then crop background region which is around brain. How could I do that in python with image processing ?. I have tried using openCV
This is the code which I tried:
def crop_brain_contour(image, plot=False):
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray,0,255,cv2.THRESH_OTSU)
ret, markers = cv2.connectedComponents(thresh)
marker_area = [np.sum(markers==m) for m in range(np.max(markers)) if m!=0]
largest_component = np.argmax(marker_area)+1
brain_mask = markers==largest_component
brain_out = image.copy()
brain_out[brain_mask==False] = (0,0,0)
gray = cv2.GaussianBlur(gray, (5, 5), 0)
thresh = cv2.threshold(gray, 45, 255, cv2.THRESH_BINARY)[1]
thresh = cv2.erode(thresh, None, iterations=2)
thresh = cv2.dilate(thresh, None, iterations=2)
cnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
c = max(cnts, key=cv2.contourArea)
# extreme points
extLeft = tuple(c[c[:, :, 0].argmin()][0])
extRight = tuple(c[c[:, :, 0].argmax()][0])
extTop = tuple(c[c[:, :, 1].argmin()][0])
extBot = tuple(c[c[:, :, 1].argmax()][0])
new_image = image[extTop[1]:extBot[1], extLeft[0]:extRight[0]]
return new_image
These images are similar that i required:
When i run this code i get this image
Thank you for the help!!
Here is one approach in Python/OpenCV.
- Read the input
- Convert to grayscale
- Threshold
- Apply morphology close
- Get the largest contour
- Draw the largest contour as white filled on a black background as a mask
- OPTIONALLY: erode the mask
- Get the dimensions of the contour (after optional eroding)
- Crop the input image and mask to those dimensions
- Put the mask into the alpha channel of the image to make the outside transparent
- Save the results
import cv2
import numpy as np
# load image
img = cv2.imread('mri.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# threshold
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)[1]
# apply morphology
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))
thresh = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)
# get external contour
contours = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours = contours[0] if len(contours) == 2 else contours[1]
big_contour = max(contours, key=cv2.contourArea)
# draw white filled contour on black background as mask
mask = np.zeros_like(thresh, dtype=np.uint8)
cv2.drawContours(mask, [big_contour], 0, 255, -1)
# get bounds of contour
x,y,w,h = cv2.boundingRect(big_contour)
# crop image and mask
img_crop = img[y:y+h, x:x+w]
mask_crop = mask[y:y+h, x:x+w]
# put mask in alpha channel of image
result = cv2.cvtColor(img_crop, cv2.COLOR_BGR2BGRA)
result[:,:,3] = mask_crop
# save resulting masked image
cv2.imwrite('mri_thresh.png', thresh)
cv2.imwrite('mri_cropped.png', img_crop)
cv2.imwrite('mri_cropped_alpha.png', result)
# ALTERNATE ERODE mask
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (11,11))
thresh2 = cv2.morphologyEx(mask, cv2.MORPH_ERODE, kernel)
# get external contour
contours2 = cv2.findContours(thresh2, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours2 = contours2[0] if len(contours2) == 2 else contours2[1]
big_contour2 = max(contours2, key=cv2.contourArea)
# draw white filled contour on black background as mask
mask2 = np.zeros_like(thresh2, dtype=np.uint8)
cv2.drawContours(mask2, [big_contour2], 0, 255, -1)
# get bounds of contour
x,y,w,h = cv2.boundingRect(big_contour2)
# crop image and mask
img_crop2 = img[y:y+h, x:x+w]
mask_crop2 = mask2[y:y+h, x:x+w]
# put mask in alpha channel of image
result2 = cv2.cvtColor(img_crop2, cv2.COLOR_BGR2BGRA)
result2[:,:,3] = mask_crop2
# save results
cv2.imwrite("mri_thresh.png", thresh)
cv2.imwrite("mri_cropped.png", img_crop)
cv2.imwrite("mri_cropped_alpha.png", result)
cv2.imwrite("mri_thresh2.png", thresh2)
cv2.imwrite("mri_cropped2.png", img_crop2)
cv2.imwrite("mri_cropped_alpha2.png", result2)
# display result
cv2.imshow("thresh", thresh)
cv2.imshow("mask", mask)
cv2.imshow("result", result)
cv2.imshow("thresh2", thresh2)
cv2.imshow("mask2", mask2)
cv2.imshow("result2", result2)
cv2.waitKey(0)
cv2.destroyAllWindows()
Input:
Threshold image:
Mask image:
Simple crop of image:
Cropped image with alpha channel:
Cropped image with alpha channel with optional erode:

How to remove a right noise from this image?

kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5,5))
close = 255 - cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel, iterations=2)
cv2.imshow('thresh', thresh)
I am assuming you wish to have only the middle part of the image and remove everything else from the image. One simple way is to search for contours, select the bounding box of the biggest contour and draw it out on a newly created mask.
Example code:
import cv2
import numpy as np
img = cv2.imread("1.png")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_OTSU+cv2.THRESH_BINARY_INV)[1]
contours = cv2.findContours(thresh, cv2.CHAIN_APPROX_NONE, cv2.RETR_TREE)[0]
cnt = max(contours, key=lambda c: cv2.contourArea(c))
mask = np.ones((img.shape[:2]), np.uint8)*255
x, y, w, h = cv2.boundingRect(cnt)
mask[y:y+h, x:x+w] = gray[y:y+h, x:x+w]
cv2.imwrite("mask.png", mask)
cv2.imshow("mask", mask)
cv2.waitKey(0)
cv2.destroyAllWindows()
EDIT:
This is how I would try to make it based on your input image
import cv2
import numpy as np
img = cv2.imread('1.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray, (3, 3), 0)
thresh = cv2.threshold(
blur, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]
contours = cv2.findContours(thresh, cv2.CHAIN_APPROX_NONE, cv2.RETR_TREE)[0]
cnt = max(contours, key=lambda c: cv2.contourArea(c))
mask = np.ones((img.shape[:2]), np.uint8)*255
mask2 = np.zeros((img.shape[:2]), dtype=np.uint8)
cv2.drawContours(mask, [cnt], -1, (0, 0, 0), -1)
x, y, w, h = cv2.boundingRect(cnt)
mask2[y:y+h, x:x+w] = gray[y:y+h, x:x+w]
cv2.imshow('mask2', mask2)
cv2.imshow('mask', mask)
cv2.waitKey(0)
cv2.destroyAllWindows()

Morphology connected image to contour mask image, error?

Here is my and I want to do mask and get this as
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY)[1]
# use morphology to close figure
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (35,35))
morph = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel, )
# find contours and bounding boxes
mask = np.zeros_like(thresh)
cv2.waitKey(0)
contours = cv2.findContours(morph, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours = contours[0] if len(contours) == 2 else contours[1]
for count in contours:
cv2.drawContours(mask, [count], 0, 255, -1)
So..Please tell how can I get this output?
how do I remove this black patch ?

How can i remove everything on an image except for the text in python?

I have an image with measurements that I need to read with python and right now it reads the most text but not all because some lines are in the way. I cant use the original image so I made an image that looks like the one I'm using.
def erode(img):
kernel = np.ones((3,3), np.uint8)
eroded = cv2.erode(img, kernel, iterations=1)
gray = cv2.cvtColor(eroded,cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray,50,150,apertureSize = 3)
minLineLength = 10
maxLineGap = 1
lines = cv2.HoughLinesP(edges,1,np.pi/180,120,minLineLength,maxLineGap)
for line in lines:
for x1,y1,x2,y2 in line:
cv2.line(eroded,(x1,y1),(x2,y2),(255,255,255),7)
I have tried using the OpenCV function houghLinesP and drawing a line over these but this doesn't remove all lines and still leaves some dots all over the place like this:
what I want is to give something like this as input:
and get something like this as an output:
the reason I need to remove all the lines but not change the
text is because I need to save the text coordinates.
The idea is to dilate and connect the text together to form a single contour. From here we can find contours and filter using a minimum threshold area. If it passes this filter then we have a desired text ROI to keep and we draw this ROI onto a mask
import cv2
import numpy as np
image = cv2.imread('3.png')
mask = np.ones(image.shape, dtype=np.uint8) * 255
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5,5))
dilate = cv2.dilate(thresh, kernel, iterations=3)
cnts = cv2.findContours(dilate, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
area = cv2.contourArea(c)
if area < 5000:
x,y,w,h = cv2.boundingRect(c)
mask[y:y+h, x:x+w] = image[y:y+h, x:x+w]
cv2.imshow('thresh', thresh)
cv2.imshow('dilate', dilate)
cv2.imshow('mask', mask)
cv2.waitKey()

Categories

Resources