Luxo_Jr
Luxo_Jr

Reputation: 411

Calculating Average Width of Specific Dark Region

I am processing a large portion of images that are similar to the one below. I'd like to be able to calculate an average width of the black line (roughly the yellow line in the image), but am not sure how best to accomplish this in python. The yellow line itself is not present on the images, just the black bands.

enter image description here

The original image:

enter image description here

Upvotes: 0

Views: 189

Answers (1)

Ahx
Ahx

Reputation: 8005

The first approach is using line-detector.


  • Find the edges of your image

    • img = cv2.imread('calculate_width.png')
      gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
      canny_img = cv2.Canny(gray_img, threshold1=150, threshold2=200)
      
    • enter image description here
  • Detect the lines

    • lines = createFastLineDetector(_length_threshold=20).detect(canny_img)
      
  • Calculate the distance

    • for cur in lines:
          (x1, y1, x2, y2) = cur[0]
          dist = math.sqrt(((x2 - x1) ** 2) + ((y2 - y1) ** 2))
          print("Distance between ({:.2f}, {:.2f}) - ({:.2f}, {:.2f}) = {:.2f}"
                .format(x1, y1, x2, y2, dist))
          cv2.line(img, pt1=(x1, y1), pt2=(x2, y2), color=(0, 255, 0),
                   thickness=2)
          cv2.imshow("detected", img)
          cv2.waitKey(0)
      
  • Result

    • enter image description here

    • Distance between (46.98, 884.00) - (50.37, 905.10) = 21.37 pixel
      

Update


If we apply the image-segmentation we have to the following area:

enter image description here

  • We want to find the length of the red lines and find the distance between the red-lines using the formula.

The upper:

enter image description here

Distance between (118.06, 868.42) - (96.92, 871.40)
Distance between (95.94, 872.67) - (75.85, 876.11) 
Distance between (74.88, 877.33) - (24.85, 886.16) 
Distance between (23.96, 887.62) - (0.01, 890.06) 

The lower:

enter image description here

Distance between (79.07, 894.60) - (99.02, 892.15)
Distance between (104.01, 886.54) - (125.99, 887.20)
Distance between (40.93, 901.45) - (66.05, 898.40)
Distance between (0.00, 906.02) - (33.99, 905.52) 

If you randomly select two points: (66.05, 898.40) and (24.85 - 886.16), the distance will be: 41.23

The solution is not perfect, but it might give an intuition for a better idea. Therefore I'm posting as an answer.

Code:

import cv2
import math
import numpy as np
from cv2.ximgproc import createFastLineDetector

img = cv2.imread('calculate_width.png')
gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray_img, 150, 255,
                            cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)
kernel = np.ones((5, 5), np.uint8)
opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel)
sure_bg = cv2.dilate(opening, kernel)
dist_transform = cv2.distanceTransform(opening, cv2.DIST_L2, 5)
_, sure_fg = cv2.threshold(dist_transform, 0.3*dist_transform.max(),
                           255, 0)
sure_fg = np.uint8(sure_fg)
unknown = cv2.subtract(sure_bg, sure_fg)

lines = createFastLineDetector(_length_threshold=20).detect(unknown)

for cur in lines:
    (x1, y1, x2, y2) = cur[0]
    dist = math.sqrt(((x2 - x1) ** 2) + ((y2 - y1) ** 2))
    print("Distance between ({:.2f}, {:.2f}) - ({:.2f}, {:.2f})"
          .format(x1, y1, x2, y2))
    cv2.line(img, pt1=(x1, y1), pt2=(x2, y2), color=(0, 255, 0),
             thickness=2)
    cv2.imshow("detected", img)
    cv2.waitKey(0)

Upvotes: 1

Related Questions