user20384021
user20384021

Reputation:

(Python , OpenCV) Extract picture from picture

I want to extract each sticker 5x6 and to total 30 sticker like below , how do I do so
(expect pic ) https://i.sstatic.net/rIzPg.jpg
(original picture) https://i.sstatic.net/ng7oV.jpg


from below link I come up my code
How extract pictures from an big image in python

The black pixels along the top are a distraction, so are the black pixels of the QR codes. You are only interested in the white stickers.

So, take a copy of your image and threshold at a high value to give you pure white stickers surrounded by black and with black QR codes within each sticker. Now find white contours and reject black ones.

Apply the contours found on the thresholded image to your original image.

I'm doing the Thresholding expecting pure white stickers surrounded by black and with black QR codes within each sticker

import numpy as np
import glob
import matplotlib.pyplot as plt
import skimage.io
import skimage.color
import skimage.filters

from PIL import Image
import pytesseract
import cv2 as cv
import numpy as np


def custom_blur_demo(image):
    kernel = np.array([[0, -1, 0], [-1, 5, -1], [0, -1, 0]], np.float32) #锐化
    dst = cv.filter2D(image, -1, kernel=kernel)
    cv.imwrite("/home/joy/桌面/test_11_4/sharpen_images.png", dst)
    cv.imshow("custom_blur_demo", dst)
 
src = cv.imread("/home/joy/桌面/test_11_4/original.png")
cv.namedWindow("input image", cv.WINDOW_AUTOSIZE)
cv.imshow("input image", src)
custom_blur_demo(src)


cv.waitKey(0)
cv.destroyAllWindows()


# load the image
image = skimage.io.imread("/home/joy/桌面/test_11_4/sharpen_images.png")[:,:,:3]


# image = imageio.imread(image_name)[:,:,:3]
# img = rgb2gray(image)

fig, ax = plt.subplots()
plt.imshow(image)


# convert the image to grayscale
gray_image = skimage.color.rgb2gray(image)

# blur the image to denoise
blurred_image = skimage.filters.gaussian(gray_image, sigma=1.0)

fig, ax = plt.subplots()
plt.imshow(blurred_image, cmap="gray")

# create a histogram of the blurred grayscale image
histogram, bin_edges = np.histogram(blurred_image, bins=256, range=(0.0, 1.0))

fig, ax = plt.subplots()
plt.plot(bin_edges[0:-1], histogram)
plt.title("Grayscale Histogram")
plt.xlabel("grayscale value")
plt.ylabel("pixels")
plt.xlim(0, 1.0)

# create a mask based on the threshold
t1 = 0.72
t2 = 0.05
binary_mask = blurred_image < t1 

fig, ax = plt.subplots()
plt.imshow(binary_mask, cmap="gray")

aaa = plt.imshow(binary_mask, cmap="gray")

plt.show() 


plt.savefig("/home/joy/桌面/test_11_4/sharpen_images_del_gray_part.png", aaa)


img = Image.open('/home/joy/桌面/test_11_4/sharpen_images_del_gray_part.png')
text = pytesseract.image_to_string(img, lang='eng')

print("file name" ,"final output", ".png")

print("size")

print(img.size)

print(text)

here is the output for mine Thresholding : https://i.sstatic.net/ng7oV.jpg
the product does after Thresholding but the word on every sticker seems blur (I'm going to OCR image to text every single sticker img later)

(pic 5b) in same link is how I reach for now https://i.sstatic.net/ng7oV.jpg

How to cut them in small piece, the sticker size

(expect pic ) https://i.sstatic.net/rIzPg.jpg

Upvotes: 0

Views: 965

Answers (2)

M.Armoun
M.Armoun

Reputation: 1155

This effort is probably not scientifically generalizable. Just wanted to show it doesn't need Contour-finding/Binarization. just pixel value comparison might be enough.

import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt

orig_image = cv.imread("sample.png")
gray = cv.cvtColor(orig_image, cv.COLOR_BGR2GRAY)
kernel = np.ones((3,3),np.uint8)
eroded = cv.erode(gray,kernel,iterations = 1)

def show_img(img_bgr):
    fig, ax = plt.subplots(figsize=(5, 5))
    rgb = cv.cvtColor(img_bgr, cv.COLOR_BGR2RGB)
    ax.imshow(rgb)
    return fig

def detect_top_bottom(original_img, erodded_img):
    """Detects only top and bottom row number of each row of Qr_Codes.
    """
    line_img = original_img.copy()
    height, width = erodded_img.shape
    top = 0
    top_drawn = False
    rows_range = []
    for row in range(erodded_img.shape[0]):
        for col in range(erodded_img.shape[1]):
            if np.mean(erodded_img[row,col]) > 190:
                if row - top > 3 and not top_drawn:
                    cv.line(line_img, (0, row), (width, row), (0,255,0), 2)
                    rows_range.append([row,None])
                    top_drawn = True
                top = row
                break
        else:
            if top_drawn:
                cv.line(line_img, (0, row), (width, row), (0,255,0), 2)
                rows_range[-1][1] = row
                top_drawn = False
    return line_img, rows_range


# make original image grayscale
gray = cv.cvtColor(orig_image, cv.COLOR_BGR2GRAY)
# erode image with 3x3 kernel in order to remove small noises
kernel = np.ones((3,3),np.uint8)
eroded = cv.erode(gray,kernel,iterations = 1)


line_img, rows_range = detect_top_bottom(orig_image, eroded)
# Rotate image 90 degs clockwise in order to use same function for detection
eroded_rotated_90 = cv.rotate(eroded, cv.ROTATE_90_CLOCKWISE)
line_img_rotated_90 = cv.rotate(line_img, cv.ROTATE_90_CLOCKWISE)
line_img, cols_range = detect_top_bottom(line_img_rotated_90, eroded_rotated_90)
# finally rotate 90 deg counter clockwise in to get orignal.
line_img= cv.rotate(line_img, cv.ROTATE_90_COUNTERCLOCKWISE)
fig = show_img(line_img)
fig.savefig("original_grid.png")

fig, axs = plt.subplots(len(rows_range), len(cols_range))
for i, row in enumerate(rows_range):
    for j, col in enumerate(cols_range):
        axs[i,j].axis('off')
        # just for sake of visualization conver to RGB
        # axs[i,j].imshow(orig_image[row[0]:row[1], :][:,col[0]:col[1]])  probabely is enough
        orig_sub_channels = cv.cvtColor(orig_image[row[0]:row[1], :][:,col[0]:col[1]], cv.COLOR_BGR2RGB)
        axs[i,j].imshow(orig_sub_channels)
fig.savefig("splitted_grid.png")

enter image description hereenter image description here

Upvotes: 0

Mark Setchell
Mark Setchell

Reputation: 207345

The black pixels along the top are a distraction, so are the black pixels of the QR codes. You are only interested in the white stickers.

So, take a copy of your image and threshold at a high value to give you pure white stickers surrounded by black and with black QR codes within each sticker. Now find white contours and reject black ones.

Apply the contours found on the thresholded image to your original image.

Upvotes: 1

Related Questions