Middle line between 2 contour lines in opencv python? - python

I have an image
After my code runs,
The new image is
I need to find the line between them like this
How do I do?
My code
import numpy as np
import cv2
import cv2 as cv
ima = cv2.imread('track1.pNg')
imgray = cv2.cvtColor(ima,cv2.COLOR_BGR2GRAY)
im = cv2.cvtColor(ima,cv2.COLOR_BGR2GRAY)
imm = cv2.inRange(im,(0),(49))
kernel = np.ones((5,5),np.uint8)
gradient = cv2.morphologyEx(imm, cv2.MORPH_GRADIENT, kernel)
il = cv2.dilate(gradient, kernel, iterations=7)
ol = cv2.erode(il, kernel, iterations=7)
contours,hei = cv2.findContours(ol,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
img = cv2.drawContours(ima, contours, -1, (200,255,0), 3)
cv2.imshow('window',ima)
How can i achieve this?

This answer explains how to find a line that runs between two sides of a shape. The center can be found by iteratively eroding the image.
This is the result:
This is the code I used:
import cv2
import numpy as np
img = 255-cv2.imread('/home/stephen/Desktop/PITqe.png',0)
kernel = np.ones((20,20), np.uint8)
img = cv2.erode(img, kernel, iterations=2)
size = np.size(img)
skel = np.zeros(img.shape,np.uint8)
ret,img = cv2.threshold(img,127,255,0)
element = cv2.getStructuringElement(cv2.MORPH_CROSS,(3,3))
done = False
while( not done):
eroded = cv2.erode(img,element)
temp = cv2.dilate(eroded,element)
temp = cv2.subtract(img,temp)
skel = cv2.bitwise_or(skel,temp)
img = eroded.copy()
zeros = size - cv2.countNonZero(img)
cv2.imshow('img', img)
cv2.waitKey(100)
if zeros==size:
done = True
cv2.imshow("img",skel)
cv2.waitKey(0)
cv2.destroyAllWindows()

Here is another way to skeletonize in OpenCV (without explicitly iterating) by using distance transform and top hat morphology.
Input:
import cv2
import numpy as np
# read image and invert so blob is white on black background
img = 255-cv2.imread('tall_blob.png',0)
# do some eroding of img, but not too much
kernel = np.ones((20,20), np.uint8)
img = cv2.erode(img, kernel, iterations=2)
# threshold img
ret, thresh = cv2.threshold(img,127,255,0)
# do distance transform
dist = cv2.distanceTransform(thresh, distanceType=cv2.DIST_L2, maskSize=5)
# set up cross for tophat skeletonization
kernel = cv2.getStructuringElement(cv2.MORPH_CROSS,(3,3))
skeleton = cv2.morphologyEx(dist, cv2.MORPH_TOPHAT, kernel)
# threshold skeleton
ret, skeleton = cv2.threshold(skeleton,0,255,0)
# display skeleton
cv2.imshow("skeleton",skeleton)
cv2.waitKey(0)
cv2.destroyAllWindows()
# save results
cv2.imwrite('tall_blob_skeleton.png', skeleton)

Related

Seeds segmentation in OpenCV/Python

I know that this topic has been covered before but I'm stuck.
I'm quite new and I trying to segment a seeds using Python and OpenCV
Here is my steps
And now I'm stuck on how to separate the 3 seeds in the center of the image. Then I use the distance transformation, but the result is not satisfactory (why it is hardly visible?). I don't know how to proceed further. I would like to achive something like this.
Distance transform
In more circular object dt works well but not in my case.
My code:
import cv2
from google.colab.patches import cv2_imshow
import numpy as np
img = cv2.imread('connected_seeds.jpg')
img = cv2.resize(img,(600,400))
# Gray scale
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# Blur image
blur_img = cv2.medianBlur(gray, 7)
# Thresholding
ret, thresh = cv2.threshold(blur_img, 0, 255, cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)
# Closing
kernel = np.ones((5,5), np.uint8)
closing = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel, iterations=2)
sure_bg = cv2.dilate(closing,kernel,iterations=2)
# Distance transform
dist_transform = cv2.distanceTransform(closing, cv2.DIST_L2, 5)
ret, sure_fg = cv2.threshold(dist_transform,0.5*dist_transform.max(),255,0)
here is the article I'm following:
https://learning.rc.virginia.edu/notes/opencv/

how to extract numbers from captcha image in python?

I want to extract numbers from captcha image, so I tried this code from this answer this answer:
try:
from PIL import Image
except ImportError:
import Image
import pytesseract
import cv2
file = 'sample.jpg'
img = cv2.imread(file, cv2.IMREAD_GRAYSCALE)
img = cv2.resize(img, None, fx=10, fy=10, interpolation=cv2.INTER_LINEAR)
img = cv2.medianBlur(img, 9)
th, img = cv2.threshold(img, 185, 255, cv2.THRESH_BINARY)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (4,8))
img = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)
cv2.imwrite("sample2.jpg", img)
file = 'sample2.jpg'
text = pytesseract.image_to_string(file)
print(''.join(x for x in text if x.isdigit()))
and it worked fine for this image: outPut: 436359 But, when I tried it on this image: It gave me nothing, outPut: .
How can I modify my code to get the numbers as a string from the second image?
EDIT:
I tried Matt's answer and it worked just fine for the image above. but it doesn't recognise numbers like (8,1) in image A, and number (7) in image B
image A
image B
How to fix that?
Often, getting OCR just right on an image like this has to do with the order and parameters of the transformations. For example, in the following code snippet, I first convert to grayscale, then erode the pixels, then dilate, then erode again. I use threshold to convert to binary (just blacks and whites) and then dilate and erode one more time. This for me produces the correct value of 859917 and should be reproducible.
import cv2
import numpy as np
import pytesseract
file = 'sample2.jpg'
img = cv2.imread(file)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ekernel = np.ones((1,2),np.uint8)
eroded = cv2.erode(gray, ekernel, iterations = 1)
dkernel = np.ones((2,3),np.uint8)
dilated_once = cv2.dilate(eroded, dkernel, iterations = 1)
ekernel = np.ones((2,2),np.uint8)
dilated_twice = cv2.erode(dilated_once, ekernel, iterations = 1)
th, threshed = cv2.threshold(dilated_twice, 200, 255, cv2.THRESH_BINARY)
dkernel = np.ones((2,2),np.uint8)
threshed_dilated = cv2.dilate(threshed, dkernel, iterations = 1)
ekernel = np.ones((2,2),np.uint8)
threshed_eroded = cv2.erode(threshed_dilated, ekernel, iterations = 1)
text = pytesseract.image_to_string(threshed_eroded)
print(''.join(x for x in text if x.isdigit()))

How to OCR low quality code picture with pytesseract

I have a set of pictures (sample) of the same formatted code, I've tried every thing but nothing works well.
I tried blurring, hsv, threshing, etc.
can you help me out?
import pytesseract
import cv2
imgr = cv2.imread("a.png")
img = cv2.resize(imgr, (int(imgr.shape[1] * 3), int(imgr.shape[0] * 3)), interpolation=cv2.INTER_AREA)
img = cv2.blur(img, (7, 7))
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
h, s, v = cv2.split(hsv)
cv2.imshow("", v)
cv2.waitKey(0)
p = pytesseract.image_to_string(v)
print(p)
thresh = cv2.threshold(v, 170, 255, cv2.THRESH_BINARY)[1]
cv2.imshow("", thresh)
cv2.waitKey(0)
print(pytesseract.image_to_string(thresh))
ation
below is a possible solution.
I felt that distortion was part of the problem. So I tried to "fix" that.
The result looks fine: the detection is successful.
Unfortunately, since you give only one sample, I have no way to figure out if this will work on the other ones... (probably not...) Nevertheless, you can give it a try.
Best regards,
Stéphane
Note: I use tesseract-5.0.0-alpha with the tessdata_best dataset.
Here is the output from the console:
Regression parameters for the second-degree polynomial:
[ 2.33735101e-04 -1.92211992e-01 2.43573673e+02]
=============================
Rectified image
RESULT: EG01-012R210126024
=============================
================================================
Test on the non rectified image
with the same blur, erode, threshold and
tesseract parameters
RESULT: EGO1-012R2101269
================================================
Press any key on an opened opencv window to close
And below is the program:
# Standard imports
import cv2
import numpy as np
from matplotlib import pyplot as plt
import pytesseract
pytesseract.pytesseract.tesseract_cmd = r'/usr/local/bin/tesseract'
# Read image
imgr = cv2.imread("a.png")
# Resizing, converting...
factor=3
imgr = cv2.resize(imgr, (int(imgr.shape[1]*factor ), int(imgr.shape[0]*factor)), interpolation=cv2.INTER_AREA)
# First detection in order to crop the image
# We want a detection. Not important if result is bad.
strings=pytesseract.image_to_data(imgr, lang = 'eng', config='--psm 11 --oem 3 -c tessedit_char_whitelist=ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-')
strings=strings.split('\n')
for line in strings[2:]:
s=line.split('\t')
if len(s[11])>0:
xmin=int(s[6])
break
## We crop the image to keep the interesting part...
imgr=imgr[:,np.max([0,xmin-imgr.shape[1]//10]):,:]
cv2.imshow("Cropped image",imgr)
hsv = cv2.cvtColor(imgr, cv2.COLOR_BGR2HSV)
h0, s0, Im0 = cv2.split(hsv)
w=Im0.shape[1] # From now, this is the image we will work on.
h=Im0.shape[0]
# Blob image to compute the image distortion
blob=cv2.blur(Im0,(w//3,1))
blob=cv2.normalize(blob,None,0,255,cv2.NORM_MINMAX)
blob=cv2.threshold(blob,170,255,cv2.THRESH_BINARY)[1]
cv2.imshow("Blob image",blob)
x=[]
y=[]
for i in range(w):
for j in range(h):
if blob[j,i]==0:
x.append(i)
y.append(j)
x=np.array(x)
y=np.array(y)
model = np.polyfit(x,y, 2)
print("Regression parameters for the second-degree polynomial: ")
print(model)
plt.plot(x,y,'x')
X=np.linspace(0,w)
plt.plot(X,X*X*model[0]+X*model[1]+model[2])
Ymean=np.mean(X*X*model[0]+X*model[1]+model[2])
# Remapping the cropped image with the found model parameters
map_x = np.zeros((Im0.shape[0], Im0.shape[1]), dtype=np.float32)
map_y = np.zeros((Im0.shape[0], Im0.shape[1]), dtype=np.float32)
for i in range(w):
for j in range(h):
map_x[j,i]=i
map_y[j,i]=j+i*i*model[0]+i*model[1]+model[2]-Ymean
Im1=cv2.remap(Im0, map_x, map_y, interpolation=cv2.INTER_LINEAR, borderMode=cv2.BORDER_REPLICATE)
# Actual detection on the rectified image: Im1
Im1=cv2.normalize(Im1,None,0,255,cv2.NORM_MINMAX)
blur_radius=8
threshold=120
Im1= cv2.blur(Im1, (blur_radius,blur_radius))
kernel = np.ones((4,4), np.uint8)
Im1=255-cv2.erode(255-Im1, kernel)#, cv2.BORDER_REPLICATE)
Im1=cv2.normalize(Im1,None,0,255,cv2.NORM_MINMAX)
Im1 = cv2.threshold(Im1, threshold, 255, cv2.THRESH_BINARY)[1]
cv2.imshow("Rectified image for text detection",Im1)
strings=pytesseract.image_to_string(Im1, lang = 'eng', config='--psm 11 --oem 3 -c tessedit_char_whitelist=ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-')
strings=strings.split()
strings=max(strings,key=len)
print('=============================')
print("Rectified image")
print('RESULT: ',strings)
print('=============================')
# For comparison: detection on the non rectified image
# using the same parameters:
Im2 = Im0 # whithout remapping
Im2 = cv2.normalize(Im2,None,0,255,cv2.NORM_MINMAX)
Im2 = cv2.blur(Im2, (blur_radius,blur_radius))
Im2 = 255-cv2.erode(255-Im2, kernel)#, cv2.BORDER_REPLICATE)
Im2 = cv2.normalize(Im2,None,0,255,cv2.NORM_MINMAX)
Im2 = cv2.threshold(Im2, threshold, 255, cv2.THRESH_BINARY)[1]
strings=pytesseract.image_to_string(Im2, lang = 'eng', config='--psm 11 --oem 3 -c tessedit_char_whitelist=ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-')
strings=strings.split()
strings=max(strings,key=len)
print('================================================')
print("Test on the non rectified image")
print("with the same blur, erode, threshold and")
print("tesseract parameters")
print('RESULT: ',strings)
print('================================================')
cv2.imshow("Unrectified image for text detection",Im2)
# Close windows
print("Press any key on an opened opencv window to close")
cv2.waitKey()
plt.close()
cv2.destroyAllWindows()
import cv2
import numpy as np
import pytesseract
from PIL import Image, ImageStat
# Load image
image = cv2.imread('a.png')
img=image.copy()
# Remove border
kernel_vertical = cv2.getStructuringElement(cv2.MORPH_RECT, (1,50))
temp1 = 255 - cv2.morphologyEx(image, cv2.MORPH_CLOSE, kernel_vertical)
horizontal_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (50,1))
temp2 = 255 - cv2.morphologyEx(image, cv2.MORPH_CLOSE, horizontal_kernel)
temp3 = cv2.add(temp1, temp2)
result = cv2.add(temp3, image)
# Convert to grayscale and Otsu's threshold
gray = cv2.cvtColor(result, cv2.COLOR_BGR2GRAY)
gray = cv2.GaussianBlur(gray,(5,5),0)
_,thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_OTSU | cv2.THRESH_BINARY_INV)
kernel = np.ones((3,3), np.uint8)
dilated = cv2.dilate(thresh, kernel, iterations = 5)
# Find the biggest Contour (Where the words are)
contours, hierarchy = cv2.findContours(dilated,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
Reg = []
for j in range(len(contours)-1):
for i in range(len(contours)-1):
if len(contours[i+1])>len(contours[i]):
Reg = contours[i]
contours [i] = contours[i+1]
contours [i+1] = Reg
x, y, w, h = cv2.boundingRect(contours[0])
img_cut = np.zeros(shape=(h,w))
img_cut = gray[y:y+h, x:x+w]
img_cut = 255-img_cut
# Tesseract
pytesseract.pytesseract.tesseract_cmd = r'C:\Program Files\Tesseract-OCR\tesseract.exe'
print(pytesseract.image_to_string(img_cut, lang = 'eng', config='--psm 7 --oem 3 -c tessedit_char_whitelist=ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-'))
cv2.imwrite('generator.jpg',img_cut)
cv2.imshow('img', img_cut)
cv2.waitKey()
Tesseract recognition : EGO1-012R210124 (Actually it's unfavorable, I try my best.)

Apply boundary to my image in opencv python

This is the imageI am trying to give proper shape to the images in my folder but unable to get that perfect result. Following is one type of example:
Following is the coding that I have done for my folder containing this type of images:
''''code''''
import cv2
import numpy as np
import glob
path = r'C:\Users\User\Desktop\A\*.jpg'
def k_function(image,k):
z= image.reshape((-1,4))
z=np.float32(z)
criteria = (cv2.TERM_CRITERIA_EPS+cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0)
ret,label,center=cv2.kmeans(z,k,None,criteria,10,cv2.KMEANS_RANDOM_CENTERS)
center = np.uint8(center)
res = center[label.flatten()]
res2 = res.reshape((image.shape))
return res2
def noise_function(image):
kernel = np.ones((2, 2), np.uint8)
closing = cv2.morphologyEx(image, cv2.MORPH_CLOSE,
kernel, iterations = 2)
bg = cv2.dilate(closing, kernel, iterations = 1)
dist_transform = cv2.distanceTransform(closing, cv2.DIST_L2, 0)
ret, fg = cv2.threshold(dist_transform, 0.02
* dist_transform.max(), 255, 0)
return fg
def filling(thresh):
im_floodfill = thresh.copy()
h, w = thresh.shape[:2]
mask = np.zeros((h+2, w+2), np.uint8)
cv2.floodFill(im_floodfill, mask,(60,60),255);
im_floodfill_inv = cv2.bitwise_not(im_floodfill)
n = thresh | im_floodfill_inv
return n
for i, img in enumerate(glob.glob(path)):
img1 = cv2.imread(img)
n = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)
b= k_function(n,2)
nm, thresh1 = cv2.threshold(b, 127, 255, cv2.THRESH_BINARY_INV);
fill = filling(thresh1)
noise = noise_function(fill)
cv2.imwrite(r'C:\Users\User\Desktop\New folder\image{}.jpg'.format(i),noise)
Try using copyMakeBorder to make a border. It looks like you're trying to use floodFill and I've never figured out how that is supposed to work.
import cv2
image = cv2.imread('elbow.png')
image = cv2.copyMakeBorder(image, 10, 0, 0, 10, cv2.BORDER_CONSTANT)
cv2.imwrite('elbow_border.png', image)
elbow.png:
elbow_border.png:
I would approach it a bit differently in Python/OpenCV. I would convert to HSV and threshold the saturation channel. Then use morphology open to smooth outline.
Input (cropped from your post):
import cv2
# load image as HSV and select saturation
img = cv2.imread("finger.png")
sat = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)[:,:,1]
# threshold the saturation channel
ret, thresh = cv2.threshold(sat,25,255,0)
# apply morphology open to smooth the outline
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (19,19))
smoothed = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel)
# write result to disk
cv2.imwrite("finger_smoothed.png", smoothed)
cv2.imshow("SAT", sat)
cv2.imshow("THRESH", thresh)
cv2.imshow("SMOOTHED", smoothed)
cv2.waitKey(0)
cv2.destroyAllWindows()
Result:

OpenCV - findContours on generated image doesn't work

I have an image of a graph. I perform some preprocessing functions on the image in order to extract the graph line (which works). I then, however, try to find the contour of the graph line that is found and saved as a separate image. When I do this, however, I do not get the desired results.
Graph line extracted
Contour found of the above image
import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread("/Users/2020shatgiskessell/Desktop/graph_extracting/Test_Graphs/Graph2.jpg")
h,w = img.shape[:2]
mask = np.zeros((h,w), np.uint8)
mask2 = mask = np.zeros((h,w), np.uint8)
def find_contours(image):
# Transform to gray colorspace and threshold the image
gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
_, thresh = cv2.threshold(gray,0,255,cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)
# erod then dialate image (for denoising)
kernel = np.ones((2,2),np.uint8)
opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel)
#Find contours in order of hiarchy
#CHAIN_APPROX_NONE gives all the points on the contour
_, contours, hierarchy = cv2.findContours(opening,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
return contours
#---------------------------------------------------------------
#CLEAN UP IMAGE AND JUST EXTRACT LINE
#get the biggest contour
cnt = max(find_contours(img), key=cv2.contourArea)
cv2.drawContours(mask, [cnt], 0, 255, -1)
# Perform a bitwise operation
res = cv2.bitwise_and(img, img, mask=mask)
# Threshold the image again
gray = cv2.cvtColor(res,cv2.COLOR_BGR2GRAY)
_, thresh = cv2.threshold(gray,0,255,cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)
# Find all non white pixels of image
non_zero = cv2.findNonZero(thresh)
# Transform all other pixels in non_white to white
for i in range(0, len(non_zero)):
first_x = non_zero[i][0][0]
first_y = non_zero[i][0][1]
first = res[first_y, first_x]
res[first_y, first_x] = 255
# Display the image
cv2.imwrite("extractedline.png", res)
#-------------------------------------------------------
#GET CONTOUR OF EXTRACTED LINE - NOT WORKING
i = 0
#Display contours
for contour in find_contours(res):
#approximate the contour shape
cv2.drawContours(mask2, [contour], 0, 255, -1)
res2 = cv2.bitwise_and(res,res,mask=mask2)
i = i+1
print (i)
cv2.imshow('after', mask2)

Categories