# 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.

( 2017-12-12 04:03:45 -0600 )edit

@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.

( 2017-12-12 04:09:42 -0600 )edit
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)

( 2017-12-12 04:29:10 -0600 )edit

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

Easier way to do it by using mouse event function.

( 2017-12-13 06:55:34 -0600 )edit

@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

( 2017-12-14 00:29:04 -0600 )edit

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[0]
cnt_1 = cnts[1]
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[0]
min_dist = 100000
min_idx = -1
for i in range(1, box_0.shape[0]):
if (box_0[i][0] - p[0])**2 + (box_0[i][1] - p[1])**2 < min_dist:
min_idx = i
min_dist = (box_0[i][0] - p[0])**2 + (box_0[i][1] - p[1])**2

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

# Then we get the main direction
if not cen_1[0] - cen_0[0]:
slope = 0
else:
main_direction = (cen_1[1] - cen_0[1]) / (cen_1[0] - cen_0[0])
if not cen_1[1] - cen_0[1]:
# 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[0]):
if (box_0[i][0] - p[0])**2 + (box_0[i][1] - p[1])**2 > max_dist:
max_idx = i
max_dist = (box_0[i][0] - p[0])**2 + (box_0[i][1] - p[1])**2
sec_max_dist = 0
sec_max_idx = -1
tt_lst = list(range(4))
for i in range(1, box_0.shape[0]):
if i == max_idx:
continue
if (box_0[i][0] - p[0])**2 + (box_0[i][1] - p[1])**2 > sec_max_dist:
sec_max_idx = i
sec_max_dist = (box_0[i][0] - p[0])**2 + (box_0[i][1] - p[1])**2
tt_lst.remove(0)
tt_lst.remove(sec_max_idx)

# draw cross lines
line1_points = [box_0[0], box_0[sec_max_idx]]
line1_middle = [int(np.mean((line1_points[0][0], line1_points[1][0]))),
int(np.mean((line1_points[0][1], line1_points[1][1])))]
line2_points = [box_0[tt_lst[0]], box_0[tt_lst[1]]]
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?

( 2017-12-13 03:40:52 -0600 )edit

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

( 2017-12-13 06:42:39 -0600 )edit

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

( 2017-12-14 01:50:32 -0600 )edit

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

( 2017-12-14 06:30:46 -0600 )edit

Official site

GitHub

Wiki

Documentation

## Stats

Seen: 2,427 times

Last updated: Dec 13 '17