enter image description here from PIL import Image
import pytesseract
from pdf2image import convert_from_path
import os
import pandas as pd
import numpy as np
img = cv2.imread(filename)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
cv2.imwrite('grey.png',gray)
binary,thresh1 = cv2.threshold(gray, 0, 255,cv2.THRESH_OTSU|cv2.THRESH_BINARY_INV)
cv2.imwrite('Thresh1.png',thresh1)
rect_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (15, 3))
dilation = cv2.dilate(thresh1, rect_kernel, iterations = 2)
contours, hierarchy = cv2.findContours(dilation, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
im2 = img.copy()
ROI_number = 0
for cnt in contours:
x,y,w,h = cv2.boundingRect(cnt)
ROI=im2[y:y+h, x:x+w]
print(str(w),str(h))
#cv2.putText(im2, str(h), (x,y - 10 ), cv2.FONT_HERSHEY_SIMPLEX, 0.1, (255, 0, 0), 1)
#cv2.putText(im2, str(w), (x,y + 10 ), cv2.FONT_HERSHEY_SIMPLEX, 0.1, (0, 0, 255), 1)
#cv2.imwrite('ROI_{}.png'.format(ROI_number),ROI)
cv2.rectangle(im2,(x,y),(x+w,y+h),(36,255,12),1)
ROI_number += 1
cv2.imwrite('contours1.png',im2)
How to make a filter which detect the bold lines part from image Bold text line should be the output for me .Don't know to approach this thing but i have a suggestion to get that thing in order of Binary inversion Threshold covert to get the white bigger part should come from that need suggestions regarding this Problem.
Related
I have the following code:
import cv2 as cv
import numpy as np
image = cv.imread("input1.jpg")
img_gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
img_denoised = cv.GaussianBlur(img_gray,(5,5),2)
ret, thresh = cv.threshold(img_denoised, 216, 255, cv.THRESH_BINARY)
kernel = np.ones((1,1),np.uint8)
opening = cv.dilate(thresh, kernel)
opening = cv.erode(opening, kernel)
# detect the contours on the binary image using cv.CHAIN_APPROX_NONE
contours, hierarchy = cv.findContours(image=opening, mode=cv.RETR_TREE, method=cv.CHAIN_APPROX_NONE)
for i in contours:
x, y, w, h = cv.boundingRect(i)
cv.drawContours(image, [i], -1, (0, 0, 255), 2)
cv.imshow("A.jpg", image)
cv.waitKey(0)
cv.destroyAllWindows()
Output:
enter image description here
It only shows the stars with a red contours but I want all the text to have a red contours, including the background. Here is the original file:
enter image description here
Many thanks in advance!
I messed with this a bit and the best outcome I could get was the following, I think with some tweaking you could ignore the shading, as I'm converting it to grayscale it seems to be dropping the correct contour on the shapes, but the text is working as expected;
import cv2
import numpy as np
src = cv2.imread('c:\\input1.jpg')
gray = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY)
# blur
blur = cv2.GaussianBlur(gray, (3, 3), 0)
# canny edge
canny = cv2.Canny(blur, 100, 200)
# dilate
kernel = np.ones((5, 5))
dilate = cv2.dilate(canny, kernel, iterations=1)
# find contours
contours, hierarchy = cv2.findContours(
dilate, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
# draw contours
cv2.drawContours(src, contours, -1, (0, 255, 0), 3)
cv2.imshow("a.jpg", src)
cv2.waitKey()
I have a mask for a dental x-ray here where all teeth are overlapping with each other. I want to count the number of teeth present in the image for that I want to separate overlapping tooths so I can use contour-based approach to count the number of tooths, I tried following approach but it is giving result like this
. how can I extract boundary for each tooth?
from skimage.feature import peak_local_max
from skimage.morphology import watershed
import matplotlib.pyplot as plt
from scipy import ndimage
import numpy as np
import cv2
def getImageEdge(input_image):
img_gray = input_image
image_black = np.zeros(shape=input_image.shape, dtype="uint8")
thresh = cv2.threshold(img_gray, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
thresh_copy = thresh.copy()
D = ndimage.distance_transform_edt(thresh_copy)
localMax = peak_local_max(D, indices = False, min_distance = 12, labels = thresh)
markers = ndimage.label(localMax, structure = np.ones((3, 3)))[0]
labels = watershed(-D, markers, mask = thresh_copy)
for label in np.unique(labels):
if label == 0:
continue
mask = np.zeros(img_gray.shape, dtype = "uint8")
mask[labels == label] = 255
contours, hierarchy = cv2.findContours(mask.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cv2.drawContours(image_black, contours, -1, (255, 255, 255), 1)
return image_black
inputImage = cv2.imread("/content/dentalMask.bmp")
inputImage = cv2.cvtColor(inputImage, cv2.COLOR_BGR2GRAY)
outputImage = getImageEdge(inputImage)
plt.imshow(inputImage)
plt.show()
plt.imshow(outputImage)
plt.show()
EDITED:
Based on the answer from fmw42 I have added one more image where it is showing more overlapping and failed in simple thresholding and contour-based approach.
input
output
Given your example, the following works for me in Python/OpenCV by simply thresholding and getting the contours.
Input:
import cv2
import numpy as np
# read image
img = cv2.imread("teeth.png")
# convert img to grayscale
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# threshold gray image
#thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY)[1]
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)[1]
# Get contours
cntrs = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cntrs = cntrs[0] if len(cntrs) == 2 else cntrs[1]
result = img.copy()
for c in cntrs:
cv2.drawContours(result, [c], -1, (0,0,255), 1)
count = len(cntrs)
print("")
print("count =",count)
print("")
# write results to disk
cv2.imwrite("teeth_thresh.png", thresh)
cv2.imwrite("tide_contours.png", result)
# display it
cv2.imshow("thresh", thresh)
cv2.imshow("result", result)
cv2.waitKey(0)
Contours:
Resulting Count:
count = 32
Without knowledge of the exact layout of teeth in a mouth, this task is impossible. No image processing technique can help.
Because in case of touching teeth, you can't tell two touching teeth from a two-rooted tooth.
I want to detect apples by thresholding. For this, I've converted the image to HSV then and calculated the lower and upper limit for InRange() function. Getting a binary mask out of it. Since apples will be touching each others, I'm using watershed algorithm to separate them.
The input image looks like this:
After InRange() operation and erosion, the gray image looks like this:
Applying the watershed algorithm, the output looks like this:
The problem with it is that the bottom left apples are wrongly detected. There are only 2 apples and three contours are shown and also the circle of one of them is way too much bigger. Any help ?
Here is my code,
import cv2
import numpy as np
import imutils
from scipy import ndimage
from skimage.feature import peak_local_max
from skimage.morphology import watershed
img = cv2.imread('4.jpg')
img = imutils.resize(img, width=640)
# img = cv2.pyrMeanShiftFiltering(img, 21, 51)
hsv = cv2.cvtColor(img,cv2.COLOR_BGR2HSV)
lower_1 = np.array([0,50,20])
upper_1 = np.array([80,255,255])
mask1 = cv2.inRange(hsv, lower_1, upper_1)
lower_2 = np.array([160,50,20])
upper_2 = np.array([179,255,255])
mask2 = cv2.inRange(hsv, lower_2, upper_2)
gray = mask1+mask2
kernel = np.ones((7,7),np.uint8)
gray = cv2.erode(gray,kernel,iterations = 1)
# gray = cv2.morphologyEx(gray, cv2.MORPH_OPEN, kernel)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
D = ndimage.distance_transform_edt(thresh)
localMax = peak_local_max(D, indices=False, min_distance=20,
labels=thresh)
markers = ndimage.label(localMax, structure=np.ones((3, 3)))[0]
labels = watershed(-D, markers, mask=thresh)
print("[INFO] {} unique segments found".format(len(np.unique(labels)) - 1))
for label in np.unique(labels):
if label == 0:
continue
mask = np.zeros(gray.shape, dtype="uint8")
mask[labels == label] = 255
cnts = cv2.findContours(mask.copy(), cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
c = max(cnts, key=cv2.contourArea)
((x, y), r) = cv2.minEnclosingCircle(c)
if r > 25 and r < 55:
cv2.circle(img, (int(x), int(y)), int(r), (0, 255, 0), 2)
cv2.putText(img, "{}".format(round(r)), (int(x) - 10, int(y)),
cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 255), 2)
cv2.imshow('thresh', thresh)
cv2.imshow('gray', gray)
cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
i'm trying to detect vertical lines where the pixels RGB has every color in less than 100 |Dark| , here is an example RGB (100,100,100).
import numpy as np
import cv2
img = cv2.imread('testD2.png')
lower = np.array([0, 0, 0], dtype = "uint8")
upper = np.array([100,100,100], dtype = "uint8")
mask = cv2.inRange(img, lower, upper)
img = cv2.bitwise_and(img, img, mask = mask)
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray,50,150,apertureSize = 3)
minLineLength=img.shape[1]-300
lines = cv2.HoughLinesP(image=edges,rho=0.02,theta=np.pi/500, threshold=10,lines=np.array([]), minLineLength=minLineLength,maxLineGap=100)
if lines is not None:
a,b,c = lines.shape
for i in range(a):
cv2.line(img, (lines[i][0][0], lines[i][0][1]), (lines[i][0][2], lines[i][0][3]), (0, 0, 255), 3, cv2.LINE_AA)
cv2.imshow('edges', edges)
cv2.imshow('result', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
i have to change the color of the end lines too,i mean the first and the last line.
Using cv2.findContours() may work better:
You can use cv2.findContours() and cv2.boundingRect() to identify the bars and return the information (x,y,h,w) that describes these rectangles. Here are a few examples.
If you want to only identify the lines and mark them you can do:
import cv2
import numpy as np
img = cv2.imread('oVKlP.png')
g = cv2.imread('oVKlP.png',0)
(T, mask) = cv2.threshold(g, 100, 255, cv2.THRESH_BINARY_INV)
_, contours, hierarchy = cv2.findContours(mask.copy(), cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
img = cv2.drawContours(img.copy(), contours, -1, (0,255,0), 2)
cv2.imwrite('just_contours.png',img)
Result:
If you want to display some of the line info like maybe the x value for a side of the bar you can do:
import cv2
import numpy as np
img = cv2.imread('oVKlP.png')
g = cv2.imread('oVKlP.png',0)
(T, mask) = cv2.threshold(g, 100, 255, cv2.THRESH_BINARY_INV)
_, contours, hierarchy = cv2.findContours(mask.copy(), cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
# bounds with x,y,h,w for each bar
bounds = [cv2.boundingRect(i) for i in contours]
bounds.reverse()
img = cv2.drawContours(img.copy(), contours, -1, (0,0,255), 2)
font = cv2.FONT_HERSHEY_SIMPLEX
n = 20
b = 0
for (x,y,w,h) in bounds:
cv2.circle(img, (x,y+n+10), 5, (0, 255, 0), -1, cv2.LINE_AA)
cv2.putText(img, '{0}'.format(x), (x-b, y+n), font, .6, (255, 0, 255), 2, cv2.LINE_AA)
n+=33
b+=3
cv2.imwrite('fancy_marks.png',img)
Result:
I have an invoice image, and I want to detect the text on it. So I plan to use 2 steps: first is to identify the text areas, and then using OCR to recognize the text.
I am using OpenCV 3.0 in python for that. I am able to identify the text(including some non text areas) but I further want to identify text boxes from the image(also excluding the non-text areas).
My input image is:
And the output is:
I am using the below code for this:
img = cv2.imread('/home/mis/Text_Recognition/bill.jpg')
mser = cv2.MSER_create()
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) #Converting to GrayScale
gray_img = img.copy()
regions = mser.detectRegions(gray, None)
hulls = [cv2.convexHull(p.reshape(-1, 1, 2)) for p in regions]
cv2.polylines(gray_img, hulls, 1, (0, 0, 255), 2)
cv2.imwrite('/home/mis/Text_Recognition/amit.jpg', gray_img) #Saving
Now, I want to identify the text boxes, and remove/unidentify any non-text areas on the invoice. I am new to OpenCV and am a beginner in Python. I am able to find some examples in MATAB example and C++ example, but If I convert them to python, it will take a lot of time for me.
Is there any example with python using OpenCV, or can anyone help me with this?
Below is the code
# Import packages
import cv2
import numpy as np
#Create MSER object
mser = cv2.MSER_create()
#Your image path i-e receipt path
img = cv2.imread('/home/rafiullah/PycharmProjects/python-ocr-master/receipts/73.jpg')
#Convert to gray scale
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
vis = img.copy()
#detect regions in gray scale image
regions, _ = mser.detectRegions(gray)
hulls = [cv2.convexHull(p.reshape(-1, 1, 2)) for p in regions]
cv2.polylines(vis, hulls, 1, (0, 255, 0))
cv2.imshow('img', vis)
cv2.waitKey(0)
mask = np.zeros((img.shape[0], img.shape[1], 1), dtype=np.uint8)
for contour in hulls:
cv2.drawContours(mask, [contour], -1, (255, 255, 255), -1)
#this is used to find only text regions, remaining are ignored
text_only = cv2.bitwise_and(img, img, mask=mask)
cv2.imshow("text only", text_only)
cv2.waitKey(0)
This is an old post, yet I'd like to contribute that if you are trying to extract all the texts out of an image, here is the code to get that text in an array.
import cv2
import numpy as np
import re
import pytesseract
from pytesseract import image_to_string
pytesseract.pytesseract.tesseract_cmd = r"C:\Program Files\Tesseract-OCR\tesseract.exe"
from PIL import Image
image_obj = Image.open("screenshot.png")
rgb = cv2.imread('screenshot.png')
small = cv2.cvtColor(rgb, cv2.COLOR_BGR2GRAY)
#threshold the image
_, bw = cv2.threshold(small, 0.0, 255.0, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)
# get horizontal mask of large size since text are horizontal components
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (20, 1))
connected = cv2.morphologyEx(bw, cv2.MORPH_CLOSE, kernel)
# find all the contours
contours, hierarchy,=cv2.findContours(connected.copy(),cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
#Segment the text lines
counter=0
array_of_texts=[]
for idx in range(len(contours)):
x, y, w, h = cv2.boundingRect(contours[idx])
cropped_image = image_obj.crop((x-10, y, x+w+10, y+h ))
str_store = re.sub(r'([^\s\w]|_)+', '', image_to_string(cropped_image))
array_of_texts.append(str_store)
counter+=1
print(array_of_texts)