Cut part of an Image using a point list of a polygon

Asked

Viewed 1,196 times

1

I have an image (see below) and a list of points that represent a given polygon of the image (e.g.. contours=[ [1430,2003], [1429,2003], [1428,2003], .... ]).
I want to create a new image that has only this polygon (the new image should be large enough to fit only the polygon). Thinking about this problem, I thought about the code below. However it is not optimized. Can anyone help me implement this using Opencv or have some p/ optimize suggestion?

from matplotlib.patches import Polygon
img = skimage.io.imread(IMAGE)
....    
verts=contours[0].astype(int)
p = Polygon(verts, facecolor="none", edgecolor=color)
minx=min([x[0] for x in verts])
maxx=max([x[0] for x in verts])
miny=min([x[1] for x in verts])
maxy=max([x[1] for x in verts])
new_image = np.zeros([maxx-minx+2, maxy-miny+2, 3],dtype=np.uint8)
new_image.fill(255)
x1=y1=0
for x in range(minx,maxx+1):
    y1=0
    for y in range(miny,maxy+1):
        #point = Point(x, y)
        if p.contains_points([(x, y)]): # contains(point):
            new_image[(x1, y1, 0)] = img[ (x, y, 0) ]
            new_image[(x1, y1, 1)] = img[ (x, y, 1) ]
            new_image[(x1, y1, 2)] = img[ (x, y, 2) ]
        y1+=1
    x1+=1
cut_image = Image.fromarray(new_image)
cut_image.save('out.png')

inserir a descrição da imagem aqui

1 answer

2

Program steps

  1. Load the image with Opencv
  2. Create a copy of the original image to change only the copy and keep the original in memory
  3. Converts from BGR color space to grayscale as the functions used work with grayscale
  4. Uses Canny Edges to get format borders
  5. Find the borders in the image
  6. Loop each contour found and check if the area is larger than zero, which means it is a geometric shape and not just a line.
  7. Creates rectangles from the coordinates of the formats found
  8. Use Grab Cut to remove Background (background)
  9. Creates a new image cropped from the region of interest of the contour coordinates

Sample Code

import cv2
import numpy as np
import urllib.request
import matplotlib.pyplot as plt
import imutils

def mostrar_imagem_plt(img):
    plt.imshow(img)
    plt.show()

def mostrar_imagem_cv(img):
    cv2.imshow('Imagem', img)
    cv2.waitKey(3000)

# Carregar Imagem
resp = urllib.request.urlopen("https://i.stack.imgur.com/qS3i0.jpg")
img = np.asarray(bytearray(resp.read()), dtype="uint8")
img = cv2.imdecode(img, cv2.IMREAD_COLOR)

# img = cv2.imread('C:/Users/usuario/Desktop/teste/qS3i0.png')

copia = img.copy()

# Conversão para escala de Cinza
gray = cv2.cvtColor(copia, cv2.COLOR_BGR2GRAY)
# mostrar_imagem_plt(gray)
mostrar_imagem_cv(np.hstack([copia, cv2.cvtColor(gray, cv2.COLOR_GRAY2BGR)]))
# Canny Edges, para obter as bordas
edged = cv2.Canny(gray, 30, 200)
mostrar_imagem_cv(np.hstack([copia, cv2.cvtColor(edged, cv2.COLOR_GRAY2BGR)]))


# Obter contornos, para identificar cada formato geométrico
# verifica se está utilizando OpenCV 2.X
if imutils.is_cv2():
    (conts, _) = cv2.findContours(edged.copy(), cv2.RETR_EXTERNAL,
                                 cv2.CHAIN_APPROX_NONE)

# verifica se está utilizando OpenCV 3.X
elif imutils.is_cv3():
    (_, conts, _) = cv2.findContours(edged.copy(), cv2.RETR_EXTERNAL,
                                    cv2.CHAIN_APPROX_NONE)

# Constantes do Grab Cut
bgdModel = np.zeros((1, 65), np.float64)
fgdModel = np.zeros((1, 65), np.float64)
mask = np.zeros(img.shape[:2], np.uint8)

for cnt in conts:
    #Informações de cada contorno
    area = cv2.contourArea(cnt)
    x,y,w,h = cv2.boundingRect(cnt)

    if area > 0:
        print(area, x, y, w, h)

        # Retângulos ao redor de cada formato
        cv2.rectangle(copia,(x,y),(x+w,y+h),(0,0,255),3)
        mostrar_imagem_cv(copia)

        # Grab Cut
        rect = (x, y, w, h)
        cv2.grabCut(img, mask, rect, bgdModel, fgdModel, 5, cv2.GC_INIT_WITH_RECT)

        mask2 = np.where((mask == 2) | (mask == 0), 0, 1).astype('uint8')
        gc = img.copy() * mask2[:, :, np.newaxis]
        mostrar_imagem_cv(gc)

        # Região de Interesse a partir do retangulo
        roi = gc[y:y + h, x:x + w]
        mostrar_imagem_cv(roi)

Results

Resultado 1

Resultado 2

Resultado 3

Resultado 4

Browser other questions tagged

You are not signed in. Login or sign up in order to post.