cropping image on distances using cv2 - python

I'm new to deep learning and image processing but I've implemented the following code for splitting Arabic characters, but my code does not recognize characters and it only finds the whole word.
this is the whole word that is detected by the code
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
%matplotlib inline
image = cv.imread('hamd.png')
height, width, depth = image.shape
print(image.shape)
image = cv.resize(image, dsize=(width*5, height*4), interpolation=cv.INTER_CUBIC)
print(image.shape)
gray = cv.cvtColor(image,cv.COLOR_BGR2GRAY)
ret,thresh = cv.threshold(gray,127,255,cv.THRESH_BINARY_INV)
kernel = np.ones((5,5), np.uint8)
img_dilation = cv.dilate(thresh, kernel, iterations=1)
gsblur=cv.GaussianBlur(img_dilation,(5,5),0)
ctrs, hier = cv.findContours(gsblur.copy(), cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
m = list()
sorted_ctrs = sorted(ctrs, key=lambda ctr: cv.boundingRect(ctr)[0])
pchl = list()
dp = image.copy()
for i, ctr in enumerate(sorted_ctrs):
x, y, w, h = cv.boundingRect(ctr)
cv.rectangle(dp,(x-10,y-10),( x + w + 10, y + h + 10 ),(90,0,255),9)
plt.imshow(dp)
now i wondered how can i split the character on the distances between two chars? what i mean looks like the image below:
this is what i want

Related

distortions in canny edge detection

I m currently using canny edge det. for segmentation but i am getting little distortions inside the circles as seen in the first image (such as the ones marked as red)
.
I tried to change threshold values, distortions are reduced but i started to lose some of the circles as well. how can i get rid of them?
thats the code i use:
import cv2
import numpy as np
from matplotlib import pyplot as plt
from google.colab.patches import cv2_imshow
img = cv2.imread('t1.PNG',0)
#img = cv2.medianBlur(img,5)
#img = cv2.threshold(img,0 ,255,cv2.THRESH_OTSU + cv2.THRESH_BINARY)
cv2.waitKey(0)
img = np.array(img, dtype=np.uint8)
img_gray = img#cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
cv2_imshow(img_gray)
img_blur = cv2.GaussianBlur(img_gray, (3,3), 0)
sigma=0.33
v = np.mean(img)
z= np.median(img)
l = int(max(0, (1.0 - sigma) * v))
#l=0.66*v
u = int(min(255, (1.0 + sigma) * v))
print(l)
print(u)
print(v)
print(z)
#u=1.33*v
edges = cv2.Canny(image=img_blur, threshold1=0, threshold2=10) # Canny Edge Detection
edges1 = cv2.Canny(image=img_blur, threshold1=l, threshold2=u/9, ) # Canny Edge Detection +++
edges12 = cv2.Canny(image=img_blur, threshold1=l*6, threshold2=u , L2gradient = True) # Canny Edge Detection
contours, hierarchy = cv2.findContours(edges12,
cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
cv2_imshow(edges1)
cv2.waitKey(0)
print("*-*-*")
cv2_imshow(edges12)
cv2.waitKey(0)
cv2.destroyAllWindows()

OpenCV Contour Detection in color

I'm trying to detect the optic disc in an image of the back of the eye using OpenCV and findContour, then fitEllipse, but my program isn't detecting the optic disc at all. How do I fix this? Code and images are below
import cv2
import numpy as np
from sklearn.linear_model import LinearRegression
import math
from decimal import Decimal
def find_elongation(image):
img = cv2.imread(image,0)
ret,thresh = cv2.threshold(img,127,255,0)
contour,hierarchy = cv2.findContours(thresh, 1, 2)
contours = []
for i in range(len(contour)):
if len(contour[i])>=5:
contours.append(contour[i])
cnt = contours[0]
k = cv2.isContourConvex(cnt)
ellipse = cv2.fitEllipse(cnt)
im = cv2.ellipse(img,ellipse,(0,255,0),2)
(x,y),(ma,Ma),angle = cv2.fitEllipse(cnt)
return Ma/ma
print(find_elongation('eye.png'))
print(find_elongation('eye2.png'))
print(find_elongation('eye3.png'))
Image (one of them):
I'm trying to get the brightly colored circle in the middle:
Thanks for the help!
I have developed a piece of code to implement what you have asked. It mainly uses de Value channel of the HSV color space followed by some morphological operations.
import cv2
import numpy as np
import matplotlib.pyplot as plt
# Read the image
img = cv2.imread('so.png')
# Transform the image to HSV color-space and keep only the value channel
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
h,s,v = cv2.split(hsv)
# Threshold the iamge with the 95% of the brightest possible pixels
maxVal = np.max(v)
per = 0.95
_, th = cv2.threshold(v, maxVal*per, 255, cv2.THRESH_BINARY)
# Erode the image and find the connected components
th = cv2.erode(th, np.ones((2,2), np.uint8))
n, conComp, stats, centroids = cv2.connectedComponentsWithStats(th)
# Obtain the sizes of the connectedComponents skipping the background
sizes = stats[1:,-1]
# Obtain the number of the connectedComponent with biggest size
nComp = np.argmax(sizes) + 1
# Isolate the connectedComponent and apply closing
out = np.zeros((img.shape[0], img.shape[1]), np.uint8)
out[conComp==nComp] = 1
out = cv2.morphologyEx(out, cv2.MORPH_CLOSE, np.ones((10,10)))
# Apply gradient to mask to obtain the border of the ellipse
out = cv2.morphologyEx(out, cv2.MORPH_GRADIENT, np.ones((2,2)))
# Join the border of the ellipse with the image to display it
img[out==1] = (0,0,0)
plt.imshow(cv2.cvtColor(img,cv2.COLOR_BGR2RGB))
plt.show()
I attach the output I have obtained with the picture you posted:

Recognize number on 7 segment display with OpenCV

I am trying to recognize the number on the 7 segment display.
I am using python on Jupyter notebook .
I have the 0~9 7 segment displayed number image,
and each number with . is saved seperately.
Below is the sample image of 3 ,3. ,2 , 2.
and I want to find these image on the target image.
I heard there are tools to find similar image on OpenCV.
I tried Brute-Force Matching with SIFT Descriptors and Ratio Test
but the output does not seem accurate.
import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt
img1 = cv2.imread('C:\\Users\\USER\\Desktop\\test\\deeplearningimage\\thermo\\3..png',cv2.IMREAD_GRAYSCALE) # trainImage
img2 = cv2.imread('C:\\Users\\USER\\Desktop\\test\\thermosample.jpg',cv2.IMREAD_GRAYSCALE) # queryImage
# Initiate SIFT detector
sift = cv.SIFT_create()
# find the keypoints and descriptors with SIFT
kp1, des1 = sift.detectAndCompute(img1,None)
kp2, des2 = sift.detectAndCompute(img2,None)
# BFMatcher with default params
bf = cv2.BFMatcher()
matches = bf.knnMatch(des1,des2,k=2)
# Apply ratio test
good = []
for m,n in matches:
if m.distance < 0.75*n.distance:
good.append([m])
# cv.drawMatchesKnn expects list of lists as matches.
img3 = cv2.drawMatchesKnn(img1,kp1,img2,kp2,good,None,flags=cv.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS)
plt.imshow(img3),plt.show()'
here is the output of the code above
Not sure how to proceed with this.
Any other opencv that would work for this problem?
You can use template matching after thresholding, and edge detection
import numpy as np
import matplotlib.pyplot as plt
import cv2
# Read Image
BGR = cv2.imread('input.jpg')
RGB = cv2.cvtColor(BGR, cv2.COLOR_BGR2RGB)
# Channels split
R = BGR[...,2]
G = BGR[...,1]
B = BGR[...,0]
# Threshold per channel
R[B>120] = 0
R[G>120] = 0
R[R<230] = 0
# Binarize
Binary = cv2.threshold(R, 127, 255, cv2.THRESH_BINARY)[1]
# Edge Detection
Edges = cv2.Canny(Binary, 50, 200)
# Read Template
templBGR = cv2.imread('templ.png')
templRGB = cv2.cvtColor(templBGR, cv2.COLOR_BGR2RGB)
templateGray = cv2.cvtColor(templBGR, cv2.COLOR_BGR2GRAY)
# Binarize Template
templateBinary = cv2.threshold(templateGray, 84, 255, cv2.THRESH_BINARY)[1]
# Denoise Template
templateFiltered = cv2.medianBlur(templateBinary,7)
# Resize Template
template = cv2.resize(templateFiltered, (templBGR.shape[1]//2, templBGR.shape[0]//2))
# Edge Detection Template
templateEdges = cv2.Canny(template, 50, 200)
# Extract Dimensions
h, w = template.shape
res = cv2.matchTemplate(Edges,templateEdges,cv2.TM_CCORR)
(_, _, _, maxLoc) = cv2.minMaxLoc(res)
img = RGB.copy()
cv2.rectangle(img, (maxLoc[0], maxLoc[1]), (maxLoc[0] + w, maxLoc[1] + h), (255,255,128), 2)
plt.subplot(221)
plt.imshow(RGB)
plt.title('Original')
plt.axis('off')
plt.subplot(222)
plt.imshow(Edges, cmap='gray')
plt.title('Segmented')
plt.axis('off')
plt.subplot(223)
plt.imshow(templRGB)
plt.title('Template')
plt.axis('off')
plt.subplot(224)
plt.imshow(img)
plt.title('Result')
plt.axis('off')
plt.show()
if you want to do multi-matching better to use a loop:
threshold = 0.8
Loc = np.where( res >= threshold)
for pt in zip(*Loc):
cv2.rectangle(img, (Loc[0], Loc[1]), (Loc[0] + w, Loc[1] + h), (255,255,128), 2)

Make background of image white in python with canny edge detection

I would like to change the background of this image to a white background in python. I tried canny edge detection, but it has a hard time finding the edges at the top of the product as you can see in the second picture. I tried different thresholds, but it would result in more background being not white. This is probably due to the fact that the top of the product in the image has almost the same color as the background.
Is there a method to detect a small difference like that? I also tried it with a green screen behind the product, but because of the reflective state of the product, the product turns green.
Here is my code:
import cv2
import numpy as np
from skimage import filters
import matplotlib.pyplot as plt
from os import listdir
from os.path import isfile, join
plt.rcParams['image.interpolation'] = 'nearest'
plt.rcParams['image.cmap'] = 'gray'
plt.rcParams['figure.dpi'] = 200
#== Parameters =======================================================================
BLUR = 15
CANNY_THRESH_1 = 10
CANNY_THRESH_2 = 255
MASK_DILATE_ITER = 10
MASK_ERODE_ITER = 10
MASK_COLOR = (1.0,1.0,1.0) # In BGR format
#== Processing =======================================================================
mypath = "./images"
images = [f for f in listdir(mypath) if isfile(join(mypath, f))]
#-- Read image -----------------------------------------------------------------------
for image in images:
img_loc = mypath + "/" + image
img = cv2.imread(img_loc)
# threshold
img_thresh = img
thresh = 180
img_thresh[ img_thresh >= thresh ] = 255
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
#-- Edge detection -------------------------------------------------------------------
edges = cv2.Canny(gray, CANNY_THRESH_1, CANNY_THRESH_2)
edges = cv2.dilate(edges, None)
edges = cv2.erode(edges, None)
#-- Find contours in edges, sort by area ---------------------------------------------
contour_info = []
contours, _ = cv2.findContours(edges, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)
for c in contours:
contour_info.append((
c,
cv2.isContourConvex(c),
cv2.contourArea(c),
))
contour_info = sorted(contour_info, key=lambda c: c[2], reverse=True)
max_contour = contour_info[0]
mask = np.zeros(edges.shape)
cv2.fillConvexPoly(mask, max_contour[0], (255))
#-- Smooth mask, then blur it --------------------------------------------------------
mask = cv2.dilate(mask, None, iterations=MASK_DILATE_ITER)
mask = cv2.erode(mask, None, iterations=MASK_ERODE_ITER)
mask = cv2.GaussianBlur(mask, (BLUR, BLUR), 0)
mask_stack = np.dstack([mask]*3) # Create 3-channel alpha mask
#-- Blend masked img into MASK_COLOR background --------------------------------------
mask_stack = mask_stack.astype('float32') / 255.0 # Use float matrices,
img = img.astype('float32') / 255.0 # for easy blending
masked = (mask_stack * img) + ((1-mask_stack) * MASK_COLOR) # Blend
masked = (masked * 255).astype('uint8') # Convert back to 8-bit
result_dir = "./results/" + image
cv2.imwrite(result_dir, masked) # Save

File is replicated without reason (Python, OpenCV)

First, it's hard to explain. If someone have a better title, feel free to edit/suggest.
So, I am using the next code to delete ROI's from given images.
import cv2
import os
import numpy as np
import shutil
src = (os.path.expanduser('~\\Desktop\\output\\'))
causali = os.listdir(src) # CREO LISTA CAUSALI-2
causali.sort(key=lambda x: int(x.split('.')[0]))
for file in enumerate(causali): # CONTA NUMERO DI FILE CAUSALE
#import image
image = cv2.imread(os.path.expanduser('~\\Desktop\\output\\{}'.format(file[1])))
cv2.imshow('orig',image)
cv2.waitKey(0)
#grayscale
gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
#cv2.imshow('gray',gray)
#cv2.waitKey(0)
#binary
ret,thresh = cv2.threshold(gray,127,255,cv2.THRESH_BINARY_INV)
#cv2.imshow('second',thresh)
#cv2.waitKey(0)
#dilation
kernel = np.ones((1,80), np.uint8)
img_dilation = cv2.dilate(thresh, kernel, iterations=1)
#cv2.imshow('dilated',img_dilation)
#cv2.waitKey(0)
#find contours
im2,ctrs, hier = cv2.findContours(img_dilation.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
#sort contours
sorted_ctrs = sorted(ctrs, key=lambda ctr: cv2.boundingRect(ctr)[0])
for i, ctr in enumerate(sorted_ctrs):
# Get bounding box
x, y, w, h = cv2.boundingRect(ctr)
# Getting ROI
roi = image[y:y+h, x:x+w]
if h < 25:
clean = cv2.rectangle(image,(x,y),( x + w, y + h ),(255,255,255),-1)
cv2.imwrite(os.path.expanduser('~\\Desktop\\output2\\{}.png').format(file[0]), clean)
I put a condition if h < 25 to delete the ROI I don't want to be visible in the final image.
This is source folder..
and this is the output the program give out..
As you can see, file n°8 came out as the n°7. This because the program don't find any ROI in that image which is ok for the condition.
The problem is I don't understand why it replicate the last file he worked (7 ---> 8). How can I fix this ?
In case no ROI is found it should just copy the file, not overwrite it with the last one..
Thanks
I rewrite the code, make copy before every processing, and fill them with color, now it's more clear:
import cv2
import os
import numpy as np
causali = os.listdir("causali")
causali.sort(key=lambda x: int(x.split('.')[0]))
print(causali)
for idx, fname in enumerate(causali):
fname = os.path.expanduser("causali/"+fname)
print(fname)
img = cv2.imread(fname)
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(gray,127,255,cv2.THRESH_BINARY_INV)
kernel = np.ones((1,80), np.uint8)
dilated = cv2.dilate(thresh, kernel, iterations=1)
cnts = cv2.findContours(dilated.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[-2]
cnts = sorted(cnts, key=lambda cnt: cv2.boundingRect(cnt)[0])
## make an copy first
clean = img.copy()
for i, cnt in enumerate(cnts):
x, y, w, h = cv2.boundingRect(cnt)
roi = img[y:y+h, x:x+w]
if h < 25:
#clean = cv2.rectangle(img,(x,y),( x + w, y + h ),(255,255,255),-1)
clean = cv2.rectangle(img,(x,y),( x + w, y + h ),(0,255,0),-1)
## save the "clean"
cv2.imwrite(os.path.expanduser("output/{}.png").format(idx), clean)
This is the result:

Categories