3

I am working on a torn document reconstruction project. First I tried to detect the edges of the image which contain torn document pieces and then I tried to crop the image into the pieces through the detected edges using the sample code,

import cv2
import numpy as np
img = cv2.imread("test.png")
img = cv2.imread("d:/test.jpeg")

cv2.imshow('Original Image',img)

new_img = cv2.Canny(img, 0, 505)
cv2.imshow('new image', new_img)

blurred = cv2.blur(new_img, (3,3))
canny = cv2.Canny(blurred, 50, 200)

## find the non-zero min-max coords of canny
pts = np.argwhere(canny>0)
y1,x1 = pts.min(axis=0)
y2,x2 = pts.max(axis=0)

## crop the region
cropped = new_img[y1:y2, x1:x2]
cv2.imwrite("cropped.png", cropped)

tagged = cv2.rectangle(new_img.copy(), (x1,y1), (x2,y2), (0,255,0), 3, cv2.LINE_AA)
cv2.imshow("tagged", tagged)
cv2.waitKey()

my input image was enter image description here

after running the above code i gets a output like enter image description here

can someone help me to crop the torn document pieces and assign them into variables

  • Have a look at [contours](https://docs.opencv.org/3.4.2/d4/d73/tutorial_py_contours_begin.html) and/or [Connected Components](https://docs.opencv.org/3.0-beta/modules/imgproc/doc/structural_analysis_and_shape_descriptors.html#connectedcomponents) – Rick M. Mar 12 '19 at 12:28
  • Have you heard the phrase ‘garbage in garbage out’? If you start with high-quality images which are well-light and with high-contrast between foreground/background the problem will get a whole lot easier and the results will also be a lot higher quality. – DisappointedByUnaccountableMod Mar 12 '19 at 21:46

1 Answers1

8

The beginning of my workflow is similar to yours. First step: blur the image..

blurred = cv2.GaussianBlur(gray, (5, 5), 0) # Blur

blur Second step: get the canny image...

canny = cv2.Canny(blurred, 30, 150) # Canny

canny Third step: draw the contours on the canny image. This closes the torn pieces.

# Find contours
_, contours, _ = cv2.findContours(canny,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
# Draw contours on canny (this connects the contours
cv2.drawContours(canny, contours, -1, 255, 2)
canny = 255 - canny

closed by drawing contours Fourth step: floodfill (the floodfilled areas are gray)

# Get mask for floodfill
h, w = thresh.shape[:2]
mask = np.zeros((h+2, w+2), np.uint8)
# Floodfill from point (0, 0)
cv2.floodFill(thresh, mask, (0,0), 123);

floodfill

Fifth step: get rid of the really small and really large contours

# Create a blank image to draw on
res = np.zeros_like(src_img)
# Create a list for unconnected contours
unconnectedContours = []
for contour in contours:
    area = cv2.contourArea(contour)
    # If the contour is not really small, or really big
    if area > 123 and area < 760000:
        cv2.drawContours(res, [contour], 0, (255,255,255), cv2.FILLED)
        unconnectedContours.append(contour)

no small contours

Finally, once you have segmented the pieces, they can be nested.

enter image description here

Stephen Meschke
  • 2,820
  • 1
  • 13
  • 25
  • Hi what image should i define in variable res @Stephen – Kaveesha Chethiyawardena Mar 16 '19 at 19:06
  • 1
    @KaveeshaChethiyawardena The 'res' image is a black image the same size as the source image. The only use of the 'res' image is to show the user the contours that are considered to be scraps of paper. I made an edit to the post to make that more clear. – Stephen Meschke Mar 16 '19 at 22:06