Yazan Alatoom
Yazan Alatoom

Reputation: 185

how to calculate distance between 2 red pixel

I have a video file with 2 dot laser and I want to calculate the distance in pixels between them, I tried this code with OpenCV, but it is not working :

Image


import cv2
import numpy as np

cap = cv2.VideoCapture('D:\Books\Pav Man\PICS\Test\VID_20200609_195155.mp4')
#cap = cv2.VideoCapture(0)
old = 0

while (1):

    # Take each frame
    ret, frame = cap.read()
    hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)

    lower_red = np.array([0, 0, 255])
    upper_red = np.array([255, 255, 255])
    mask = cv2.inRange(hsv, lower_red, upper_red)
    cv2.imshow('mask', mask)
    # cv2.imshow('Track Laser', frame)
    moments = cv2.moments(hsv[:, :, 2])


    output = cv2.connectedComponentsWithStats(mask, 8, cv2.CV_32S)


    print (output[3])
    print ("----**----")
    if moments["m00"] > 0:
        x = (moments['m10']/ moments['m00'])
        y = (moments['m01']/ moments['m00'])
        #print(moments['m00'],moments['m01'],moments['m10'])
        #print(x, y)

    if cv2.waitKey(1) & 0xFF == ord('q'):
        break




cap.release()
cv2.destroyAllWindows()

this code output = cv2.connectedComponentsWithStats(mask, 8, cv2.CV_32S) give me the centroid of points , but how to geat each point(laser dot) separately ? if I get the centroid I can measure the distance between these points

Upvotes: 0

Views: 1714

Answers (4)

Alex Alex
Alex Alex

Reputation: 2018

You can do this:

  1. The function cv2.InRange() to find two red dots.
  2. The function cv2.connectedComponentsWithStats() to find the centroids of these red points.
  3. Calculate the Euclidean distance between centroids.

Also, you can select points by brightness only, without even using their color.

import cv2 

img = cv2.imread('HAgbc.jpg')
gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
cv2.normalize(gray, gray,  0, 255, cv2.NORM_MINMAX, cv2.CV_8UC1)
points=cv2.threshold(gray, 230, 255, cv2.THRESH_BINARY )[1]
output = cv2.connectedComponentsWithStats(points, 8, cv2.CV_32S)
centroids = output[3]
x,y=(centroids[1]-centroids[2])
dist=cv2.magnitude(x, y)[0]
print('distance is: ', *dist)

Or this code (find two brightness maximum):

import cv2 

img = cv2.imread('HAgbc.jpg')
gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
pos1=cv2.minMaxLoc(gray)[3]
cv2.circle(gray, pos1, 30, 0, -1) # masking first spot
pos2=cv2.minMaxLoc(gray)[3]
x=pos1[0]-pos2[0]
y=pos1[1]-pos2[1]
dist=cv2.magnitude(x, y)[0]
print('distance is: ', *dist)

Upvotes: 0

fmw42
fmw42

Reputation: 53079

Here is your other way to do that in Python/OpenCV using connectedComponentsWithStats.

  • Read the input
  • Set min and max red colors
  • Use cv2.inRange() to threshold on the color range
  • Apply morphology open and close to clean up small spots and holes
  • Process with connectedComponentsWithStats to get the labels and centroids
  • Extract all the areas corresponding to the labels and centroids
  • For all labels, test if the area is smaller than some estimate of the background, as we want to exclude that centroid. Draw the label as a filled yellow region on a copy of the input. Extract the centroids of small regions and store in pts array. Draw the centroids as small green squares on the copy of the input.
  • For all saved points, compute the distance between successive ones.
  • Save the output


Input:

enter image description here

import cv2
import numpy as np
import math

# read image
frame = cv2.imread('red_spots.jpg')
hh, ww = frame.shape[:2]

# convert to hsv   hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)

# threshold image
lower_red = np.array([0, 0, 225])
upper_red = np.array([255, 255, 255])
thresh = cv2.inRange(hsv, lower_red, upper_red)

# apply close and open morphology to smooth
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (9,9))
morph = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)
morph = cv2.morphologyEx(morph, cv2.MORPH_OPEN, kernel)

# do connected components processing
nlabels, labels, stats, centroids = cv2.connectedComponentsWithStats(morph, None, None, None, 8, cv2.CV_16U)

# get all areas from stats[label_start_id:label_stop_id, area_flag] 
areas = stats[0:, cv2.CC_STAT_AREA]

# draw labels and get centroids and draw centroids
result = frame.copy()
pts = []
for i in range(0, nlabels):
    if areas[i] <= ww*hh/5 :
        # labels start at 1 not 0
        result[labels == i+1] = (0,255,255)
        pt = centroids[i]
        pts.append(pt)
        cx = pt[0]
        cy = pt[1]
        x = int(round(cx))
        y = int(round(cy))
        # draw small square at centroids
        result[y-2:y+3,x-2:x+3] = (0,255,0)
        print('centroid =',cx,",",cy)

number = len(pts)   
for i in range(number-1):
    pt1 = pts[i]
    x1 = pt1[0]
    y1 = pt1[1]
    pt2 = pts[i+1]
    x2 = pt2[0]
    y2 = pt2[1]
    dist = math.sqrt( (x2-x1)**2 + (y2-y1)**2 )
    print('distance =', dist)
    print('')

#save images
cv2.imwrite('red_spots_thresh2.jpg',thresh)
cv2.imwrite('red_spots_morph2.jpg',morph)
cv2.imwrite('red_spots_centroids2.jpg',result)

# show images
cv2.imshow("thresh", thresh)
cv2.imshow("morph", morph)
cv2.imshow("result", result)
cv2.waitKey(0)
cv2.destroyAllWindows()


Threshold image:

enter image description here

Morphology cleaned image:

enter image description here

Result image with colored region labels and centroids:

enter image description here

Centroids and Distances:

centroid = 1006.7307283673711 , 433.70499350726004
centroid = 1036.418693371483 , 750.4024797329519
distance = 318.08595229553544


Upvotes: 1

fmw42
fmw42

Reputation: 53079

Here is one way to do your processing in Python/OpenCV using contours.

  • Read the input
  • Set min and max red colors
  • Use cv2.inRange() to threshold on the color range
  • Apply morphology open and close to clean up small spots and holes
  • Find contours
  • For each contour, draw the contour, use moments to compute the centroid, save the centroids in a list and draw a small square at the centroid location
  • For each successive pair of centroid points, compute the distance between them in pixels
  • Save the results


Input:

enter image description here

import cv2
import numpy as np
import math

# read image
frame = cv2.imread('red_spots.jpg')

# convert to hsv   hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)

# threshold image
lower_red = np.array([0, 0, 225])
upper_red = np.array([255, 255, 255])
thresh = cv2.inRange(hsv, lower_red, upper_red)

# apply close and open morphology to smooth
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (9,9))
morph = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)
morph = cv2.morphologyEx(morph, cv2.MORPH_OPEN, kernel)

# draw contours and get centroids
spots = frame.copy()
contours = cv2.findContours(morph, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours = contours[0] if len(contours) == 2 else contours[1]
pts = []
count = 0
for c in contours:
    cv2.drawContours(spots, [c], -1, (0,255,0), 2)
    M = cv2.moments(c)
    cx = M["m10"] / M["m00"]
    cy = M["m01"] / M["m00"]
    pt = (cx,cy)
    pts.append(pt)
    x = round(cx)
    y = round(cy)
    # draw small square at centroids
    spots[y-2:y+3,x-2:x+3] = (255,0,0)
    print('centroid =',cx,",",cy)
    count = count + 1

for i in range(count-1):
    pt1 = pts[i]
    x1 = pt1[0]
    y1 = pt1[1]
    pt2 = pts[i+1]
    x2 = pt2[0]
    y2 = pt2[1]
    dist = math.sqrt( (x2-x1)**2 + (y2-y1)**2 )
    print('distance =', dist)
    print('')

#save images
cv2.imwrite('red_spots_thresh.png',thresh)
cv2.imwrite('red_spots_morph.png',morph)
cv2.imwrite('red_spots_centroids.png',spots)

# show images
cv2.imshow("thresh", thresh)
cv2.imshow("morph", morph)
cv2.imshow("spots", spots)
cv2.waitKey(0)
cv2.destroyAllWindows()


Threshold image:

enter image description here

Morphology cleaned image:

enter image description here

Contours and centroids image:

enter image description here

Centroids and Distances:

centroid = 1036.4038142620232 , 750.3941127694858
centroid = 1006.6605586230609 , 433.9662237323787
distance = 317.8227024875417


Upvotes: 0

fmw42
fmw42

Reputation: 53079

Distance is the square root of the sum of the squares of the x difference and the y difference. So

import math

dist = math.sqrt( (x1-x2)**2 + (y1-y2)**2 )


for points x1,y1 and x2,y2

Upvotes: 1

Related Questions