-1

I have an Image showing below: enter image description here

I need to crop the order using python coding. What I need is only the card. So I want to crop the border. How to do it??

This is the output I got using the code mentioned in the below comment.

enter image description here

Shaon Paul
  • 153
  • 1
  • 2
  • 14
  • Maybe my answer to this question could help: https://stackoverflow.com/questions/51360609/single-image-cropping-or-spliting-into-multiple-images-in-python/51362159#51362159 . Though not the exact same situation, it seems close. – mahesh Jul 17 '18 at 15:06

3 Answers3

0

You could try using the Python Image Library PIL

from PIL import Image
img = Image.open("ImageName.jpg")
area_top = (125,70,444,253)
cropped_img_top = img.crop(area_top)
cropped_img_top.show()

img = Image.open("ImageName.jpg")
area_bottom = (125,306,444,490)
cropped_img_bottom = img.crop(area_bottom)
cropped_img_bottom.show()

if you want to edit multiple pictures automatically you could use following program which crops all .jpg files in the same folder as your python file:

import os
from PIL import Image
files = os.listdir()

for image_name in files:
    if ".jpg" in image_name:
        img = Image.open(image_name)
        area_top = (125, 70, 444, 253)
        cropped_img_top = img.crop(area_top)
        cropped_img_top.save("cropped_top_"+image_name)

        area_bottom = (125, 306, 444, 490)
        cropped_img_bottom = img.crop(area_bottom)
        cropped_img_bottom.save("cropped_bottom_"+image_name)

Edit: Ok, if you want it to find the corners itself you could try the following code. I just implemented a really basic corner finding algorithm which works fine on the image you provided, but I don't know how your other images look like so there might be problems there. It also took me a long time to code, so please use with appreciation ;)

Here is the code:

import os
from PIL import Image
import numpy as np


def convolution2d(matrix, kernel):
    m, n = kernel.shape
    y, x = matrix.shape
    y = y - m + 1
    x = x - m + 1
    new_matrix = np.zeros((y, x))
    for i in range(y):
        for j in range(x):
            new_matrix[i][j] = np.sum(matrix[i:i + m, j:j + m] * kernel)
    return new_matrix


def widen(mask, amount):
    return np.array([[mask[0][0]] * amount + [mask[0][1]] * amount] * amount +
                    [[mask[1][0]] * amount + [mask[1][1]] * amount] * amount)


def too_close(existing, new, max_dist):
    for c in existing:
        if (c[0] - new[0]) ** 2 + (c[1] - new[1]) ** 2 < max_dist ** 2:
            return True
    return False


def corner(bw, mask, corner_threshold, offset):
    corner_hotmap = convolution2d(bw, mask)
    corner_threshold = np.max(corner_hotmap) * corner_threshold
    width = len(corner_hotmap)
    height = len(corner_hotmap[0])
    corners = []
    for x in range(width):
        for y in range(height):
            if corner_hotmap[x][y] > corner_threshold:
                if not too_close(corners, [x, y], 10):
                    corners.append([x + offset, y + offset])
    return corners


def get_areas(image, brightness_threshold=100, corner_threshold=0.9, n_pix=4):
    width = len(image)
    height = len(image[0])
    greyscale = np.zeros(shape=(width, height))
    for x in range(width):
        for y in range(height):
            s = sum(image[x][y]) / 3
            if s > brightness_threshold:
                greyscale[x][y] = 1
            else:
                greyscale[x][y] = -1

    top_left = widen([[-1, -1, ], [-1, 1, ]], n_pix)
    bottom_right = widen([[1, -1, ], [-1, -1, ]], n_pix)

    corners_topleft = corner(greyscale, top_left, corner_threshold, n_pix)
    corners_bottomright = corner(greyscale, bottom_right, corner_threshold, n_pix)

    if len(corners_topleft) != len(corners_bottomright):
        return []
    else:
        out = []
        for i in range(len(corners_topleft)):
            out.append((corners_topleft[i][1], corners_topleft[i][0], corners_bottomright[i][1],
                        corners_bottomright[i][0]))
        return out


files = os.listdir()

for image_name in files:
    if ".jpg" in image_name:
        img = Image.open(image_name)
        width = img.size[0]
        height = img.size[1]
        image = np.array(Image.open(image_name).getdata()).reshape(height, width, 3)
        print("Getting Areas for file {}.".format(image_name))
        areas = get_areas(image)
        if len(areas)==0:
            print("Could not find corners for file {}.".format(image_name))
        else:
            print("Found {} cards".format(len(areas)))
        for i in range(len(areas)):
            cropped_img = img.crop(areas[i])
            cropped_img.save("cropped_{}_{}".format(i, image_name))

Finding corners is not easy. This algorithm works well on the Image you provided, however I do not know how the other images look like and if this will work on those as well. Good luck with cropping your Images ^^

pascscha
  • 1,623
  • 10
  • 16
  • How to determine the area of an Image? – Shaon Paul Jul 17 '18 at 11:00
  • That depends on how you want to crop the image. If you want to crop out the first white square area would be (125,70,444,253) But if you wanted to crop out the second white square it would be (125,306,444,490) – pascscha Jul 17 '18 at 11:07
  • okay. But how you determine (125,70,444,253),(125,306,444,490) these value?? – Shaon Paul Jul 17 '18 at 11:11
  • i just opened it up in an image editing software and checked the coordinates of the corner. would you like to find the corners automatically? – pascscha Jul 17 '18 at 11:18
  • You'd have to do corner detection for that. You could use [OpenCV](https://docs.opencv.org/3.4/dc/d0d/tutorial_py_features_harris.html) for that. – pascscha Jul 17 '18 at 11:26
  • This is a great code...My last query is if I want to apply it for multiple images then how to use loop here and how can I write this code as a function.. – Shaon Paul Jul 17 '18 at 11:28
  • Yes its working but that area size I need to incorporate with the code above. Because I have many images and areas of other images may not same. So I need some function which may determine the area and I want to use it as a function and want to incorporate with the code above. Could you please help me to do that? – Shaon Paul Jul 17 '18 at 11:49
  • Does this work for you? I added a corner finding algorithm, so it should find the corners by itself now. – pascscha Jul 17 '18 at 14:36
  • This works fine for me..Just a bit curious to know how many cards are there in my original image then how to do this? – Shaon Paul Jul 18 '18 at 12:37
  • @ShaonPaul you can find out the number of carts with `len(areas)` – pascscha Jul 18 '18 at 12:56
  • @ShaonPaul I have added it to the code above. But its literally just printing out `len(areas)` should not be that hard^^ – pascscha Jul 19 '18 at 09:54
0

All you need to do is slicing arrays. First supply the startY and endY coordinates, followed by the startX and endX coordinates to the slice. That’s it. Your image will be cropped!

Steps using Python and OpenCV:

1) load the image and display it on screen

# import the necessary packages 
import cv2
# load the image and show it
image = cv2.imread("cardWithBorder.jpg")
cv2.imshow("original", image)
cv2.waitKey(0)

2) Get the dimensions of the image

print image.shape

3) Cropping the image

# crop the image using array slices -- it's a NumPy array
# after all!
cropped = image[70:170, 440:540]
cv2.imshow("cropped", cropped)
cv2.waitKey(0)

4) Save the cropped image to disk, only in PNG format (the original was a JPG):

cv2.imwrite("thumbnail.png", cropped)
Debashish Sen
  • 696
  • 5
  • 12
  • I have several cards within a same image, which I want to extract. Could you please tell me how to do that? – Shaon Paul Jul 17 '18 at 12:44
0

Maybe you can use a different approach using opencv, where you create a gray mask to get only the interesting areas of the image. You can do that like this:

#import the necessary packages
import numpy as np
import cv2

#read the image
image = cv2.imread('image.jpg')

#rgb values for grey color in pixels
lower = np.array([80,70,70],dtype='uint8')
upper = np.array([95,85,85],dtype='uint8')

#create a grey mask and then the inverse of that mask
mask = cv2.inRange(image,lower,upper)
mask_inv = cv2.bitwise_not(mask)
output = cv2.bitwise_and(image,image,mask=mask_inv)

# display the result
cv2.imshow('images',np.hstack([output]))
cv2.waitKey(0)

Assuming you want to extract cards that don't have the same shape/positioning every time, that technique might come in handy.

bowo299
  • 43
  • 6
  • I am getting an error shows : cpp:1769: error: (-209) The lower boundary is neither an array of the same size and same type as src, nor a scalar in function cv::inRange – Shaon Paul Jul 17 '18 at 12:39
  • I have several cards within a same image, which I want to extract. Could you please tell me how to do that? – Shaon Paul Jul 17 '18 at 12:42
  • That's weird; my script compiles fine in python 3.5.2 and 3.6.1. Perhaps there is sth wrong with your version? As long as the background color is the same, you will always get an image with cards only as output. Then it's just a matter of saving the correct image portion. Debug my script in your system and then work your way to save only the coloured areas in the resulting image as different cards. But if the positioning and size of the images is the same always it's better to do automated crops than recognizing color. – bowo299 Jul 17 '18 at 13:09