-3

I am browsing for days now to find a solution to this problem. No existing solution has worked yet.

Here is my problem : I scan photos, on which there are some blank spaces (that can be anywhere (top, right, left, bottom)). I would like to adjust theses photos by removing the blank spaces.

Here is an example (there's no white square on this original photo, that's just for anonymity) :

Here is the original photo.

Here, I've highlighted what I want to suppress.

And here is what I expect to be the result.

I use OpenCV to do that (Python version) but if you have a solution with another program, no problem!

Has anyone found a solution about how to perform that ?

Thank you. Have a great day !

secavfr
  • 628
  • 1
  • 9
  • 24
  • 1
    This seems an easy task but it is not. The problem is that the area you want to remove is similar in color with valid areas. Before answering I have questions: 1) could you just crop all images by a padding? 2)have you tried finding contours? – Fred Guth Jun 21 '18 at 10:50
  • Thank you fredguth. Yes I've tried (really) many codes from really many places for contours. Concerning paddings: no, it varies. – secavfr Jun 21 '18 at 11:31
  • May I know why people who put a "-1", put it ? That's one big problem on Stackoverflow : why allowing to put a "-1" without justifying anything ? – secavfr Jun 21 '18 at 12:07
  • 1
    Normally, people will put -1 if they read it and didn't understand what you wanted. But in your case, I understood easily. – Fred Guth Jun 21 '18 at 12:24
  • Thank you for the answer. Have you an idea of how to remove thoses spaces ? – secavfr Jun 21 '18 at 12:35
  • 1
    just sent my answer. ;-) – Fred Guth Jun 21 '18 at 12:36

1 Answers1

1

I used findContours to find a box that you can use to crop your image. Here is the code:

import cv2
import numpy as np


image = cv2.imread("./FH13g.jpg", cv2.IMREAD_COLOR)
blurred_image = cv2.GaussianBlur(image, (3,3), 0)
gray = cv2.cvtColor(blurred_image, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
mask = 255 - thresh

_, contours, _ = cv2.findContours(mask.copy(), cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)

maxArea = 0
best = None
for contour in contours:
  area = cv2.contourArea(contour)
  print (area)
  if area > maxArea :  
    maxArea = area
    best = contour

rect = cv2.minAreaRect(best)
box = cv2.boxPoints(rect)
box = np.int0(box)
cv2.drawContours(image, [box], 0, (0, 0, 255), 3)

while True:
  cv2.imshow("result", image)
  k = cv2.waitKey(30) & 0xff
  if k == 27:
      break
Fred Guth
  • 1,537
  • 1
  • 15
  • 27
  • Thank you for your answer ! It works almost well on the photo I've put in the question, but check those results. Would you have an idea of what parameter to change so it fits only the pictures, and not the faces ? https://imgur.com/yZXkwZg (original) https://imgur.com/FXsFQdQ (other example) https://imgur.com/5kFZQdu (other example) – secavfr Jun 21 '18 at 13:05
  • I suggest you calibrate the code. See what happens to image at every line. Explore changing the threshold in the mask. Also, you may only look contours with area at least x% of the whole image. The second example shows a box titled because this is the minarea around the contour. You can use cv2.boundingRect if you don't want to rotate the image. opencv has a good tutorial on this. – Fred Guth Jun 21 '18 at 14:37
  • Besides, all examples seems very similar. I still think you could just drop a little bit without contours etc. – Fred Guth Jun 21 '18 at 14:40
  • Sure, I've managed to modify the "127 and 255" values to "185 and 250" in the threshold. It works well. Thank you very much. – secavfr Jun 21 '18 at 18:35