2

Here's a receipt image that I've got and I've plotted it using matplotlib,

# x1, y1, x2, y2, x3, y3, x4, y4
bbox_coords = [[650, 850], [1040, 850], [1040, 930], [650, 930]]

image = cv2.imread(IMG_FILE)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

fig, ax = plt.subplots(figsize=(20, 20))
ax.imshow(gray, cmap='Greys_r'); 
rect = Polygon(bbox_coords, fill=False, linewidth=1, edgecolor='r')
ax.add_patch(rect)
plt.show()

print(gray.shape)
(4376, 2885)

receipt image

Then, I've cropped the original gray image and plotted it again with same bounding box coordinates and here's the result,

# cropped the original image    
gray_new = gray[25:4314, 147:2880] 

fig, ax = plt.subplots(figsize=(20, 20))
ax.imshow(gray_new, cmap='Greys_r'); 
rect = Polygon(bbox_coords, fill=False, linewidth=1, edgecolor='r')
ax.add_patch(rect)
plt.show()

print(gray_new.shape)
(4289, 2733)

cropped receipt

So, I'm looking for a way to make bounding box to fit the cropped image. I couldn't figure out how I can achieve it.

Edit:

Here's an another image if you want to replicate the question, receipt-2 and these are the b-box coordinates for the image [1638,1462,2974,1462,2974,1549,1638,1549].

user_12
  • 1,778
  • 7
  • 31
  • 72

2 Answers2

4

If you cropped 25 pixels on the left and 147 pixels on the top then you have to substract 25 pixels from all X values and 147 pixels from Y values because all elemenets on image moved 25 pixel to the left and 147 pixels to the top.

box_coords = [
    [650-25,  850-147],
    [1040-25, 850-147],
    [1040-25, 930-147],
    [650-25,  930-147]
]

print(bbox_coords)

EDIT: Using code

bbox_coords = [[650, 850], [1040, 850], [1040, 930], [650, 930]]

bbox_coords = [[x-25, y-147] for x,y in bbox_coords]

print(bbox_coords)

BTW: and it doesn't matter how many pixels you cropped on right and bottom.


EDIT: Calculation for rescaling image

Calculate size which keep proportions

old_width = 4376
old_height = 2885
new_width = 550
#new_height = 270 # doesn't keep proportion
new_height = int(new_width/(old_width/old_height)) # keep proportion

print('new size:', new_width, new_height)
print('proportions:', (old_width/old_height), (new_width/new_height))

new_image = resize(original_img, shape=(new_width, new_height))

Calculate position when image change size (I assume that it doesn't keep proportions).

scale_x = old_width/new_width
scale_y = old_height/new_height

print('scale:', scale_x, scale_y)

bbox_coords = [[int(x/scale_x), int(y/scale_y)] for x,y in bbox_coords]

print(bbox_coords)

If image keeps propotion then scale_x == scale_y and you can calculate and use only one scale for all values.

furas
  • 134,197
  • 12
  • 106
  • 148
  • Thank you :) ..Actually for me, x-147, and y-25 is giving me the correct bounding box like the below answer. Am I doing something wrong? – user_12 Jan 09 '20 at 09:43
  • Just one more similar doubt that I have, here I have manually cropped the result but in my project I'm also resizing the image like `resize(original_img, shape=(550, 270))` here the resize functions automatically converts `(4376, 2885)` to `(550, 270)` then how can I find the new bounding box values? – user_12 Jan 09 '20 at 11:14
  • first: you don't keep aspect ration `(4376/2885, 550/270)` gives `(1.5, 2.0)` so you deform page. It should have height `550/(4376/2885)` which gives `362`. Second: you have to calculate scales `scale_x = 4376/550`, `scale_y = 2885/270` (gives `sx=7.95, sy=10.68`) and you divide all `X` by `scale_x` and all `Y` by `scale_y`. – furas Jan 09 '20 at 12:46
  • 1
    I added calculations to answer. – furas Jan 09 '20 at 13:02
  • I tried the solution but it's giving me wrong bounding boxes. – user_12 Jan 09 '20 at 13:17
  • did you use `new_height = 270` if you resized to `(550, 270)` ? – furas Jan 09 '20 at 13:20
  • Sorry it was my mistake. I got it now. I calculated it with cropped height and weight. Thank you so much again. – user_12 Jan 09 '20 at 13:29
1

You have to move the coordinates of the Polygon, the same quantity that you cropped in x and in y coordinates.

Take into account that when you apply gray_new = gray[25:4314, 147:2880], this means [rows, columns], so for the plot, you are removing the first 25 pixels on y axis and the first 147 pixels on x axis.

The results would be

bbox_coords = [[x - 147, y-25] for x, y in bbox_coords]

and in values:

bbox_coords = [[503, 825], [893, 825], [893, 925], [503, 925]]
pypadawan
  • 36
  • 3