Ask Your Question
0

How to crop rectangles from a image with opencv

asked 2020-01-22 10:00:37 -0500

Agustin gravatar image

i have this code, i need to crop each rectangle from the next images but in some cases this code doesn't work:

import cv2
import os
import pytesseract
from PIL import Image

lista = os.listdir('C:/Users/Usuario/Documents/Deteccion de Objetos/recortes')

#busco la ultima carpeta creada de los recortes

ultimo = lista.pop()
convertido = int(ultimo)

path = 'C:/Users/Usuario/Documents/Deteccion de Objetos/recortes/' + ultimo

image = cv2.imread(
        "C:/Users/Usuario/Documents/Deteccion de Objetos/imagenes/Nuevacarpeta/sqlserver.png")
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    blur = cv2.GaussianBlur(gray, (5,5), 0)
    thresh = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]

# Remove dotted lines
cnts = cv2.findContours(thresh, cv2.RETR_EXTERNAL, 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:
        cv2.drawContours(thresh, [c], -1, (0,0,0), -1)

# Fill contours
close_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5,5))
close = 255 - cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, close_kernel, iterations=6)
cnts = cv2.findContours(close, 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 < 15000:
        cv2.drawContours(close, [c], -1, (0,0,0), -1)

# Smooth contours
close = 255 - close
open_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (20,20))
opening = cv2.morphologyEx(close, cv2.MORPH_OPEN, open_kernel, iterations=3)

# Busca los contornos y dibuja los resultados
ROI_number = 0
cnts = cv2.findContours(opening, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
    cv2.drawContours(image, [c], -1, (36,255,12), 3)
    #aqui se realiza el recorte de cada entidad
    x,y,w,h = cv2.boundingRect(c)
    ROI = image[y:y+h, x:x+w]
    cv2.imwrite(os.path.join(path , 'imagen_{}.png'.format(ROI_number)), ROI)
    cv2.rectangle(image,(x,y),(x+w,y+h),(36,255,12),2)
    ROI_number += 1


#formo una lista con las imagenes de la ultima carpeta creada
listadeimagenes = os.listdir(path)
print(listadeimagenes)

nuevo = str(convertido + 1).zfill(7)

os.chdir('C:/Users/Usuario/Documents/Deteccion de Objetos/recortes')
os.mkdir(nuevo)

print("Cantidad de entidades ", len(cnts))
cv2.imshow('thresh', thresh)
cv2.imshow('opening', opening)
cv2.imshow('image', image)
cv2.waitKey()

if someone can run my code with this examples you will see my problem

these are some example of the image from i need to crop the rectangle, but only the rectangle:

image description image descriptionimage description(https://i.stack.imgur.com/fTkes.png)(...)

edit retag flag offensive close merge delete

2 answers

Sort by » oldest newest most voted
0

answered 2020-02-10 10:11:00 -0500

Agustin gravatar image

this is the full code. you can see i need to crop each rectangle but also i need to extract the text from each rectangle.

import cv2
import re
import os
import pytesseract
from PIL import Image

# obtengo la direccion donde se encuentra los recortes

lista = os.listdir('C:/Users/Usuario/Documents/Deteccion de Objetos/recortes')

# busco la ultima carpeta creada de los recortes

ultimo = lista.pop()
convertido = int(ultimo)

path = 'C:/Users/Usuario/Documents/Deteccion de Objetos/recortes/' + ultimo

# miro y busco la imagen que necesito para examinar
image = cv2.imread(
    "C:/Users/Usuario/Documents/Deteccion de Objetos/imagenes/Nuevacarpeta/ejemplo4.png")
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray, (5, 5), 0)
thresh = cv2.threshold(
    blur, 127, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]


# Remove dotted lines
cnts = cv2.findContours(thresh, cv2.RETR_EXTERNAL, 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:
        cv2.drawContours(thresh, [c], -1, (0, 0, 0), -1)

# Fill contours
close_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))
morph = 255 - cv2.morphologyEx(thresh, cv2.MORPH_CLOSE,
                               close_kernel, iterations=6)
cnts = cv2.findContours(morph, 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 < 15000:
        cv2.drawContours(morph, [c], -1, (0, 0, 0), -1)

# Smooth contours
close = 255 - morph
open_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (20, 20))
opening = cv2.morphologyEx(close, cv2.MORPH_OPEN, close_kernel, iterations=3)

# Busca los contornos y dibuja los resultados
ROI_number = 0
cnts = cv2.findContours(opening, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
    #cv2.drawContours(image, [c], -1, (36, 255, 12), 3)
    # aqui se realiza el recorte de cada entidad
    x, y, w, h = cv2.boundingRect(c)
    ROI = image[y:y+h, x:x+w]
    cv2.imwrite(os.path.join(path, 'imagen_{}.png'.format(ROI_number)), ROI)
    cv2.rectangle(image, (x, y), (x+w, y+h), (36, 255, 12), 2)
    ROI_number += 1

# formo una lista con las imagenes de la ultima carpeta creada
listadeimagenes = os.listdir(path)
print(listadeimagenes)

# aqui realizo el reconociemiento de texto dentro de cada entidad
for imagenes in listadeimagenes:
    preprocess = "thresh"
    img = cv2.imread(path + "/" + imagenes)
    cv2.imshow('imagen de la ruta', img)
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    if (preprocess == "thresh"):
        gray = cv2.threshold(
            gray, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
    elif (preprocess == "blur"):
        gray = cv2.medianBlur(gray, 3)
    filename = "{}.png".format(os.getpid())
    cv2.imwrite(filename, gray)

    imgtext = Image.open(filename)

    pytesseract.pytesseract.tesseract_cmd = 'C:/Program Files (x86)/Tesseract-OCR/tesseract.exe'
    # limpio el codigo de caracteres que no corresponden
    texto = pytesseract.image_to_string(imgtext)
    text = re.sub(r'[^\da-zA-Z0-9_() \n]+', '', texto)

    print("-------------------------------------------------------------------")
    print("   *  *  T E X T    D E T E C T E D  *  *")
    print("-------------------------------------------------------------------")
    if text:
        print("No está vacía")
        contenidolineas = text.splitlines()
        palabras = contenidolineas[0].split(" ")
        mensaje2 = ""
        for i in contenidolineas:
            if (contenidolineas.index(i) == 0):
                mensaje2 = mensaje2 + f"Entidad: " + contenidolineas[0]
            else:
                mensaje2 = mensaje2 + f ...
(more)
edit flag offensive delete link more

Comments

I will try it. Unfortunately, unable to used namespace import os, because of Spanish language. I will try work around.

supra56 gravatar imagesupra56 ( 2020-02-10 21:48:07 -0500 )edit

You may have to play around with value. It will extract rectangle text too. But it may not work well in your code.

if area < 50000:
supra56 gravatar imagesupra56 ( 2020-02-11 07:49:30 -0500 )edit
0

answered 2020-02-04 06:37:45 -0500

supra56 gravatar image

updated 2020-02-05 09:03:51 -0500

Using mouseevent. It is straight forward. It will save iterator files

  1. Drag rectangle
  2. Press "s" to save
  3. Press "r" to rest
  4. Do step 1 to 3
  5. Press "c" to exit.

Code:

import cv2 as cv

refPt = []
cropping = False

def click_crop(event, x, y, flags, param):
    global refPt, cropping, num
    if event == cv.EVENT_LBUTTONDOWN:
        refPt = [(x, y)]
        cropping = True

    if event == cv.EVENT_LBUTTONUP:
        num += 1
        refPt.append((x, y))
        cropping = False        
        cv.rectangle(img, refPt[0], refPt[1], (0, 255, 0), 2)

if __name__ == "__main__":
    num = 0

    windowName = 'Click and Crop'
    img = cv.imread('text.png', cv.IMREAD_COLOR)
    clone = img.copy()
    cv.namedWindow(windowName)

    cv.setMouseCallback(windowName, click_crop)

    num = 0
    if len(refPt) == 2:
        num += 1

    while True:
        cv.imshow(windowName, img)
        key = cv.waitKey(1)
        if key == ord("r"): 
            img = clone.copy()
        elif key == ord("s"):   
            roi = clone[refPt[0][1]:refPt[1][1], refPt[0][0]:refPt[1][0]]
            cv.imwrite('roi{}.jpg'.format(num), roi)            
        elif key == ord("c"):  
            break    
    cv.destroyAllWindows()

Output:

image description image description image description image description

@Agustin. Don't used cv2.drawContours. You get both rectangles. I am not going to post screenshot for cropped. I merely got 2 images. Second images contained purple rectangle and 3rd image contained heavy grey border. I am running out of my time. I will attempt to get it back sooner.

import cv2

image = cv2.imread('text.png')
#image = cv2.imread('text4.png')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray, (5,5), 0)
thresh = cv2.threshold(blur, 127, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]

# Fill contours
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5,5))
morph = 255 - cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel, iterations=3)
#morph = 255 - cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel, iterations=6)

close = 255 - morph 
opening = cv2.morphologyEx(close, cv2.MORPH_OPEN, kernel, iterations=3)

# Busca los contornos y dibuja los resultados
ROI_number = 0
cnts = cv2.findContours(opening, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
    x,y,w,h = cv2.boundingRect(c)
    ROI = image[y:y+h, x:x+w]

    cv2.rectangle(image,(x,y),(x+w,y+h),(36,255,12),2)
    cv2.imwrite('images_{}.png'.format(ROI_number), ROI)
    ROI_number += 1 

print("Cantidad de entidades ", len(cnts))
cv2.imshow('thresh', thresh)
cv2.imshow('opening', blur)
cv2.imshow('image', image)
cv2.waitKey()

Output: for text:

image description

Output for text4 using iterations=6:

image description

edit flag offensive delete link more

Comments

The first image is better and 4th image slightly, so i had iterator to 6. The drawContours will merely drew around text but not whitespaces. So that why I don't like it. I will attempt to get 2nd and 3rd image.

supra56 gravatar imagesupra56 ( 2020-02-05 09:06:10 -0500 )edit

hello, i tried it but it doesnt work, also i tried with another image but it doesn work very well, i show you the image and the result

Agustin gravatar imageAgustin ( 2020-02-10 09:58:22 -0500 )edit

I tested it with another image that you posted. It will extract each text rectangles w/out using `pytesseract. Also can cropped too. I used same as above but not with mouse event.

supra56 gravatar imagesupra56 ( 2020-02-11 06:59:29 -0500 )edit
Login/Signup to Answer

Question Tools

1 follower

Stats

Asked: 2020-01-22 10:00:37 -0500

Seen: 133 times

Last updated: Feb 10