# How do I draw a scale inside the bounding box?

I want to measure the dimension of the objects in a image.

This is my original image These are bounding box that I have drawn around the detected objects As can be seen even the shadow is being detected as area under the interested object.

Unfortunately, I doubt manipulating the image in any way can help me minimise the error in me detecting a wrong dimension.

I would like to draw draw small lines inside on two sides of the bounding box as can seen on the ruler image below Which definitely will help me get a accurate measurement without manipulating the original image in any way

Can any suggestion how this can be done?

edit retag close merge delete

1

for accurate measurement first you need a camera calibration and second either an object with known size or a fixed working distance. Doing this you are able to compare the real world with the virtual one. Otherwise its not possible.

@VxW Considering that the about conditions are met. I just want to draw small lines(as seen on ruler in mm) on two sides of the inside the bounding box.

1

you can iterate along the lines using LineIterator (see here), calculate the normal vector and draw the lines using cv::lines. Additionally you will need a scale parameter of your iteration steps (distance between the small ruler lines)

Sort by » oldest newest most voted

I solved it 😊

This is the solution I was looking for though I couldn't extend the lines from the points. This solves my problem.  Just found the length of the line segment.

Then used the m:n ratio of dividing the line segment at pre set interval

Find the point's coordinates, then draw a set circle at the point

10 line code I guess anyone can do it after they get the idea

more

@supra56 No manual intervention. It has to detect the object by itself and draw out such a scale. I just cropped the image as I couldn't upload the entire pic Hi, I've drawn one line in my poor code T_T, but I don't have time now to transform it into the iterative one: draw parallel lines along the shorter side to divide the rect into 2, 4, 8, ... parts, hope this can help you a bit:)

I'll try to spare time to turn it into a iterative one.

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

gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

ret, thr = cv2.threshold(gray, 127, 255, cv2.THRESH_OTSU)
_, contours, _ = cv2.findContours(thr, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
small_cnts = [i for i in contours if cv2.contourArea(i) < 100]
cv2.fillPoly(thr, small_cnts, 0)
_, cnts, _ = cv2.findContours(thr, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
cnts = sorted(cnts, key=lambda x: cv2.contourArea(x))
cnts.pop()

img_cp = img.copy()
[cv2.drawContours(img_cp, contours, i, (255, 0, 0), thickness=3) for i in range(len(contours))]
plt.imshow(cv2.cvtColor(img_cp, cv2.COLOR_BGR2RGB))
plt.show()

cnt_0 = cnts
cnt_1 = cnts
rect_0 = cv2.minAreaRect(cnt_0)
rect_1 = cv2.minAreaRect(cnt_1)
box_0 = cv2.boxPoints(rect_0).astype(np.int0)
box_1 = cv2.boxPoints(rect_1).astype(np.int0)
cv2.drawContours(img_cp, [box_0], 0, (0, 255, 0), 5)
_ = cv2.drawContours(img_cp, [box_1], 0, (0, 255, 0), 5)
plt.imshow(cv2.cvtColor(img_cp, cv2.COLOR_BGR2RGB))
plt.show()

# get the 2 points at two shortest borders
p = box_0
min_dist = 100000
min_idx = -1
for i in range(1, box_0.shape):
if (box_0[i] - p)**2 + (box_0[i] - p)**2 < min_dist:
min_idx = i
min_dist = (box_0[i] - p)**2 + (box_0[i] - p)**2

cen_0 = [np.mean((box_0[min_idx], p)), np.mean((box_0[min_idx], p))]
t_lst = list(range(4))
t_lst.remove(0)
t_lst.remove(min_idx)
cen_1 = [np.mean((box_0[t_lst], box_0[t_lst])), np.mean((box_0[t_lst], box_0[t_lst]))]

# Then we get the main direction
if not cen_1 - cen_0:
slope = 0
else:
main_direction = (cen_1 - cen_0) / (cen_1 - cen_0)
if not cen_1 - cen_0:
# slope doesn't exist
pass
else:
slope = 1/main_direction

# get sec_max_point
max_dist = 0
max_idx = -1
for i in range(1, box_0.shape):
if (box_0[i] - p)**2 + (box_0[i] - p)**2 > max_dist:
max_idx = i
max_dist = (box_0[i] - p)**2 + (box_0[i] - p)**2
sec_max_dist = 0
sec_max_idx = -1
tt_lst = list(range(4))
for i in range(1, box_0.shape):
if i == max_idx:
continue
if (box_0[i] - p)**2 + (box_0[i] - p)**2 > sec_max_dist:
sec_max_idx = i
sec_max_dist = (box_0[i] - p)**2 + (box_0[i] - p)**2
tt_lst.remove(0)
tt_lst.remove(sec_max_idx)

# draw cross lines
line1_points = [box_0, box_0[sec_max_idx]]
line1_middle = [int(np.mean((line1_points, line1_points))),
int(np.mean((line1_points, line1_points)))]
line2_points = [box_0[tt_lst], box_0[tt_lst]]
line2_middle = [int(np.mean ...
more @Santhosh1. I want to measure the dimension of the objects in a image. Is that what you want to measured size? C:\fakepath\pen_box.jpg

I can do rectangle between two sides on ruler.

more

@supra56 Yes exactly what I am looking for, How did you remove the shadow part?

@Santhosh1. I didn't remove shadow. It is still exactly. Is that ur pen?

@supra56 Its a challenge in itself, to detect an object in an image. Yeah it is my pen.

Can you tell me measurement of sizes(both pen and cover)? Preferably, inch, mm and cm

Official site

GitHub

Wiki

Documentation