I want to crop the image along the contour instead of the rectangle [python OpenCV]

Purpose

I want to get the outline of an object in an image with OpenCV and cut it out. When I examine it, I can only find patterns that are cut out with circumscribing rectangles and squares, even with various contours. I want to cut out only the object as it is.

Way of thinking

The only way to crop an image with OpenCV + python is to specify the pixel range of the original image, such as img [10: 100, 20: 100].

So, first cut out with the circumscribing rectangle, then make a canvas with the circumscribing rectangle size, Data is organized in the acquired contour information, and the maximum value and the minimum value are acquired for each row and made into an array. On the transparent canvas created earlier, line by line, if you go between the minimum and maximum, get it from the original image and plot it ..., It seems that we should repeat it line by line.

Go!

code

import cv2
import numpy as np
from pprint import pprint
from copy import deepcopy
import sys
import os


#Grayscale conversion of input image> Binarization, return the binarized image
def getBinary(im):
    im_gray = cv2.cvtColor(im , cv2.COLOR_BGR2GRAY) 
    return cv2.threshold(im_gray, 0, 255, cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)[1] 

#Get the circumscribing rectangle
def getBoundingRectAngle(contour):
    #Since the array structure is multiple, make it a simple array once(point [x y])
    contour = list(map(lambda point: point[0], contour))
    x_list = [ point[0] for point in contour ] # width
    y_list = [ point[1] for point in contour ] # height
    return  [min(x_list), max(x_list), min(y_list), max(y_list)]

#Cut out
def getPartImageByRect(img, rect):
    #[y-axis, x-axis]
    return img[ rect[2]:rect[3], rect[0]:rect[1],]

def getCropData(contour, main_axis=0):
    target_axis =  1  if main_axis == 0 else 0

    #axis = 0 = x 
    #axis = 1 = y 
    contour = list(map(lambda i: i[0], contour))
    

    axis_point_list = set([ point[main_axis] for point in contour ]) # unique
    arr = []

    for val in axis_point_list:
        #Get an array of x with a specific value of y from the contour array
        target_axis_point_list = list(filter(lambda i: i[main_axis] == val, contour))
        tmp_list = [ i[target_axis] for i in target_axis_point_list ] # 
        arr.append( [ val, min(tmp_list), max(tmp_list)] )
    return arr

##Get the x-coordinate range along the y-axis
def doCropY(input_im,  points, rect) :
    height = rect[3]-rect[2]
    width = rect[1]-rect[0] 
    left = rect[0]    
    top = rect[2]
    output_im = np.zeros((height, width, 4), np.uint8)

    for point in points :
        for x in range(0, width) :
            #input image coordinates
            in_y = point[0]
            in_x = x + left
            in_x_min = point[1]
            in_x_max = point[2]

            #output image coordinates
            out_y = point[0] - top
            out_x = x
            out_x_min = point[1] - left
            out_x_max = point[2] - left

            #Copy from the original image to the new image if it is within the maximum and minimum range of the x-axis
            if( out_x_min < x  and x < out_x_max):
                output_im[out_y : out_y + 1, out_x : out_x + 1, ] = input_im[in_y : in_y + 1, in_x : in_x + 1, ]
    return output_im


##For the image that has been extracted once
##Get the y-coordinate range along the x-axis
def doCropX(im, points, rect):
    height = rect[3]-rect[2]
    width = rect[1]-rect[0] 
    left = rect[0]    
    top = rect[2]

    for point in points :
        for y in range(0, height) :
            #input image coordinates
            y = y
            x = point[0] - left
            y_min = point[1] - top
            y_max = point[2] - top            
            #Copy from the original image to the new image if it is within the maximum and minimum range of the y-axis
            if(  y < y_min  or y_max < y):
                im[y:y+1, x:x+1,] = [0,0,0,0] #Transparent
    return im

##########################
#  main
##########################
outdir = './out/'
tempdir = './temporary/'

#Get image path from argument
args = sys.argv
if(len(args) <= 1):
    print("need arg 1. input file path.")
    sys.exit()
src_file = args[1]
root, extention = os.path.splitext(src_file)

#Image loading
im_src = cv2.imread(src_file, -1) #Alpha channel included
# cv2.imwrite(tempdir + "original" + extention, im_src)

#Get the contour as binary
im_bin = getBinary(im_src)

#contours = cv2.findContours(im_bin, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)[0]
contours = cv2.findContours(im_bin, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)[0] #Get all paths

for i, cnt in  enumerate(contours):
    #Get the circumscribing rectangle
    rect = getBoundingRectAngle(cnt)
    #Cut in the range of the left and right edges of x in the y coordinate
    crop_data  = getCropData(cnt, 1) #x-axis reference
    im_out = doCropY(im_src, crop_data, rect)
    
    # # #Makes the outside of the range from the top to the bottom of y transparent for each x coordinate
    crop_data  = getCropData(cnt, 0) #x-axis reference
    im_out = doCropX(im_out, crop_data, rect)

    cv2.imwrite(outdir + "out" + str(i) + extention, im_out)

move

python3 crop.py filename

Intermediate file output to temporary / Output the image file cut out to out /

sample

Input image

Cut out image

It may be confusing that the background of the circumscribing rectangle is transparent ...

Recommended Posts

I want to crop the image along the contour instead of the rectangle [python OpenCV]
I made a function to crop the image of python openCV, so please use it.
How to crop the lower right part of the image with Python OpenCV
I tried to find the entropy of the image with python
I tried "gamma correction" of the image with Python + OpenCV
I want to know the features of Python and pip
I want to read the html version of "OpenCV-Python Tutorials" OpenCV 3.1 version
I want to output the beginning of the next month with Python
I want to check the position of my face with OpenCV!
(Python Selenium) I want to check the settings of the download destination of WebDriver
I want to batch convert the result of "string" .split () in Python
I want to explain the abstract class (ABCmeta) of Python in detail.
Python: I want to measure the processing time of a function neatly
I tried "smoothing" the image with Python + OpenCV
I tried "differentiating" the image with Python + OpenCV
How to crop an image with Python + OpenCV
I tried to correct the keystone of the image
I tried "binarizing" the image with Python + OpenCV
I want to customize the appearance of zabbix
I tried using the image filter of OpenCV
I want to display the progress in Python!
[Python + OpenCV] Whiten the transparent part of the image
[Python] I tried to judge the member image of the idol group using Keras
I want to use Python in the environment of pyenv + pipenv on Windows 10
I want to grep the execution result of strace
[OpenCV / Python] I tried image analysis of cells with OpenCV
I want to inherit to the back with python dataclass
I want to fully understand the basics of Bokeh
I want to write in Python! (3) Utilize the mock
I want to use the R dataset in python
Python OpenCV tried to display the image in text.
I want to increase the security of ssh connections
I tried to summarize the string operations of Python
I want to use Linux commands at the command prompt! Use Linux commands at the command prompt instead of Git Bash
I want to initialize if the value is empty (python)
maya Python I want to fix the baked animation again.
I want to start a lot of processes from python
I want to use only the normalization process of SudachiPy
I want to get the operation information of yahoo route
[Python] I want to use the -h option with argparse
[Python] I tried to visualize the follow relationship of Twitter
I want to judge the authenticity of the elements of numpy array
Keras I want to get the output of any layer !!
I want to know the legend of the IT technology world
[Python] I want to make a 3D scatter plot of the epicenter with Cartopy + Matplotlib!
Introduction to image analysis opencv python
I want to debug with Python
I want to get the name of the function / method being executed
I want to manually assign the training parameters of the [Pytorch] model
I want to know the weather with LINE bot feat.Heroku + Python
[Python] Try to graph from the image of Ring Fit [OCR]
I tried to build the SD boot image of LicheePi Nano
I tried to process the image in "sketch style" with OpenCV
I want to run the Python GUI when starting Raspberry Pi
I wrote the code to write the code of Brainf * ck in python
I tried to display the video playback time (OpenCV: Python version)
I want to use both key and value of Python iterator
I just erased the object using image repair (inpaint) (OpenCV: Python)
I tried to process the image in "pencil style" with OpenCV
I want to know the population of each country in the world.
I tried to improve the efficiency of daily work with Python