File is replicated without reason (Python, OpenCV) - python

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:

Related

How to iterate/loop over a folder of images in opencv?

I am trying to loop over a folder of images in OpenCv. Each images is a line of text. I would like to segment each line into words and then save each word as an image. I have used the following code which works well on a single image at a time. But when I try to apply it on all the files in the folder, it just exports one of them and doesn't start looping over them all.
I'll appreciate your help and thank you in advance.
ayaasiin
from PIL import Image
import cv2
import numpy as np
from pathlib import Path
import glob
corpus_dir = Path('data')
files = list(corpus_dir.glob(pattern='*.jpg'))
files
for f in files:
image = Image.open(f)
image = cv2.imread(str(f))
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray,(5,5),0)
ret, thresh1 = cv2.threshold(blur, 0, 255, cv2.THRESH_OTSU |
cv2.THRESH_BINARY_INV)
cv2.imwrite('threshold_image.jpg',thresh1)
rect_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (4,30))
dilation = cv2.dilate(thresh1, rect_kernel, iterations = 6)
cv2.imwrite('dilation_image.jpg',dilation)
contours, hierarchy = cv2.findContours(dilation, cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
im2 = img.copy()
crop_number=1
cnt = sorted(contours, key=lambda x: cv2.boundingRect(x)[1:])
for cnt in contours:
x, y, w, h = cv2.boundingRect(cnt)
if h > 50 and w > 50:
roi = im2[y:y+h, 0:x]
#Draw the bounding box on the text area
rect = cv2.rectangle(im2, (x, y), (x + w, y + h), (0, 255, 0), 2)
​
​
# Crop the bounding box area
cropped = im2[y:y + h, x:x + w]
cv2.imwrite("sawir "+str(crop_number)+".jpeg",cropped)
crop_number+=1

Problem in cropping a bounding box out of an image [duplicate]

This question already has answers here:
Want to find contours -> ValueError: not enough values to unpack (expected 3, got 2), this appears [duplicate]
(2 answers)
Closed last year.
My objective is to crop a bounding box out of an image using opencv's cv2 library. I've found an interesting way of doing it from here, however I am getting an error like
>ValueError: not enough values to unpack (expected 3, got 2)
This is the complete traceback:
Traceback (most recent call last):
File "text_extraction.py", line 13, in <module>
image, contours, hierarchy = cv2.findContours(mask, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
ValueError: not enough values to unpack (expected 3, got 2)
And this is my complete code:
import cv2
import numpy as np
import pytesseract
pytesseract.pytesseract.tesseract_cmd = 'C:/Program Files/Tesseract-OCR/tesseract.exe'
im = cv2.imread('detected-image-2.png')
grayimage = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
ret, mask = cv2.threshold(grayimage, 170, 255, cv2.THRESH_BINARY)
cv2.imshow('mask', mask)
image, contours, hierarchy = cv2.findContours(mask, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
for contour in contours:
if cv2.contourArea(contour) < 200:
continue
rect = cv2.minAreaRect(contour)
box = cv2.boxPoints(rect)
ext_left = tuple(contour[contour[:, :, 0].argmin()][0])
ext_right = tuple(contour[contour[:, :, 0].argmax()][0])
ext_top = tuple(contour[contour[:, :, 1].argmin()][0])
ext_bot = tuple(contour[contour[:, :, 1].argmax()][0])
roi_corners = np.array([box], dtype=np.int32)
cv2.polylines(im, roi_corners, 1, (255, 0, 0), 3)
cv2.imshow('image', im)
cv2.waitKey(0)
cropped_image = grayimage[ext_top[1]:ext_bot[1], ext_left[0]:ext_right[0]]
cv2.imwrite('crop.jpg', cropped_image)
What exactly is wrong in this code?
I am relatively new to OpenCV, please help me out.
EDIT: I even tried a way by referring to this answer however the problem still persists.
EDIT-2: upon solving the Value Error, the script was unable to save the cropped image(It was saving the image as it as). Based on statemachines code I changed the code to this:
im = cv2.imread('detected-image-2.png')
grayimage = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
ret, mask = cv2.threshold(grayimage, 170, 255, cv2.THRESH_BINARY)
cv2.imshow('mask', mask)
cv2.waitKey(0)
contours, hierarchy = cv2.findContours(mask, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
for contour in contours:
if cv2.contourArea(contour) < 200:
continue
rect = cv2.minAreaRect(contour)
box = cv2.boxPoints(rect)
X, Y, W, H = cv2.boundingRect(contour)
cropped_image = im[Y:Y + H, X:X + W]
print([X, Y, W, H])
plt.imshow(cropped_image)
cv2.imwrite('contour1.png', cropped_image)
However the output is still the same(cropping is not happening).
Solved it myself after figuring it out where I was making a mistake, in case if someone faces a similar issue, this piece of code would help.
def crop():
# reading image
image = cv2.imread("detected-image-1.png")
# converting to gray scale
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# applying canny edge detection
edged = cv2.Canny(gray, 10, 250)
# finding contours
(cnts, _) = cv2.findContours(edged.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
idx = 0
for c in cnts:
x, y, w, h = cv2.boundingRect(c)
if w > 50 and h > 50:
idx += 1
new_img = image[y:y + h, x:x + w]
# cropping images
cv2.imwrite("cropped/" + str(idx) + '.png', new_img)
print('Objects Cropped Successfully!')

cropping image on distances using cv2

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

Lines are not highlighted

I'm trying to find the outline of the lines. To further find words and symbols. But for some reason my code doesn't work and I can't figure out what it is.
I'm trying to find lines in this image Example
Here's my code
import cv2
import numpy as np
#import image
image = cv2.imread('C:\\Users\\dennn\\PycharmProjects\\untitled2\\output.jpg')
#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)
#dilation0000
kernel = np.ones((5,100), np.uint8)
img_dilation = cv2.dilate(thresh, kernel, iterations=1)
cv2.imshow('dilated',img_dilation)
cv2.waitKey(0)
#find contours
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]
# show ROI
cv2.imshow('segment no:'+str(i),roi)
cv2.rectangle(image,(x,y),( x + w, y + h ),(90,0,255),2)
cv2.waitKey(0)
cv2.imshow('marked areas',image)
cv2.waitKey(0)
My output image. The output image
I want to receive I want
I don't have sort contours working.
During the debugger, I get the following image, it is only this (the program freezes) show ROI
Here is the solution to this problem

Sort images after ROI (Python, OpenCV)

I am near new to OpenCV world. I am working on a project which need (for now) to detect numbers in an image, select them and save.
This is the code I used:
# Importing modules
import cv2
import numpy as np
# Read the input image
im = cv2.imread('C:\\Users\\User\\Desktop\\test.png')
# Convert to grayscale and apply Gaussian filtering
im_gray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
im_gray = cv2.GaussianBlur(im_gray, (5, 5), 0)
# Threshold the image
ret, im_th = cv2.threshold(im_gray, 90, 255, cv2.THRESH_BINARY_INV)
# Find contours in the image
image, ctrs, hier = cv2.findContours(im_th.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# Bounding rectangle for a set of points
i = 0
#rects = [cv2.boundingRect(ctr) for ctr in ctrs]
#rects.sort()
for ctr in ctrs:
x, y, w, h = cv2.boundingRect(ctrs[i])
# Getting ROI
roi = im[y:y+h, x:x+w]
#cv2.imshow('roi',roi)
#cv2.waitKey()
i += 1
cv2.imwrite('C:\\Users\\User\\Desktop\\crop\\' + str(i) + '.jpg', roi)
#print(rects)
print("OK - NO ERRORS")
It works a half. The problem is the output numbers (in image format, it need to be that way) aren't ordered by the original image (below).
This is the output:
What is wrong in the code ?
Also, you can note the rects variable. I used it to do some debug and I noted an interesting thing: if I sort it's content, in console the array of images order is right.
Is there a way to sort the images in the original order ?
I also saw this very similar post but I can't understand the solution.
Thank you very much.
There is no natural order given that the ROIs could be spread out in two dimensional space.
If you want to order them by x coordinate you could do:
sorted_ctrs = sorted(ctrs, key=lambda ctr: cv2.boundingRect(ctr)[0])
and then loop over sorted_ctrs instead of ctrs.
Edit: More precisely:
import cv2
import numpy as np
# Read the input image
im = cv2.imread('JnUpW.png')
# Convert to grayscale and apply Gaussian filtering
im_gray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
im_gray = cv2.GaussianBlur(im_gray, (5, 5), 0)
# Threshold the image
ret, im_th = cv2.threshold(im_gray, 90, 255, cv2.THRESH_BINARY_INV)
# Find contours in the image
image, ctrs, hier = cv2.findContours(im_th.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# Sort the bounding boxes
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 = im[y:y+h, x:x+w]
# Write to disk
cv2.imwrite(str(i) + '.jpg', roi)
#print(rects)
print("OK - NO ERRORS")

Categories