2

So I have a temperature box where I am trying to pinpoint the coordinate location of a small triangle on each temperature dial. Here are the examples of the box with slight variations:

[

I have been able to isolate each dial, get their outlines and centers. I then have an algorithm that will generate an angle measure from the center point and then the eventually found point on the triangle. However, I have been unable, so to speak, "find" solely the triangle using OpenCV. I've been able to outline it and such but cannot figure out how to isolate just it's lines. I have tried multiple shape detection and edge detection blocks of code but have had no luck because its so lightly raised from the actual dial. If I can just get a point on the dial that would be good enough even.

5
  • find the circles, polar transform to get an unrolled "ring" on the knob, analyze 1D signal. -- or work with that screwdriver slot in the middle of each dial. Commented Jul 21, 2022 at 15:54
  • Ya so I've been able to find the dials, make a ring around them, find the center and do the calculation for the angle I just can't get the the reference point somewhere on that triangle. And while finding edges of the screwdriver slot would work for 180 degrees it wont work here because it could mean the complete opposite direction exp: 20 == 55 Commented Jul 21, 2022 at 16:16
  • You can use image matching. Take photos of dials in every state, and then compare them to one on the photo. Commented Jul 21, 2022 at 16:51
  • When you worry about the opposite direction, it means that number of candidates is only 2. Therefore, all you need to do is determine which is the triangle. e.g. if compare the edge strength of them, stronger one may be the triangle. Or, checking image correlation between candidate region and other region which is not candidate may have more robustness. Commented Jul 22, 2022 at 2:05
  • That makes sense I think, I don't know if I'd know how to put that into code however. If you have an example I can miniplate that would be awesome, if not no worries. Commented Jul 23, 2022 at 3:38

1 Answer 1

1

There are several possible approaches you can try in order to find the direction of the dial. In this answer I will try it with classic contour detection. However a well trained ML model can be much more robust and reliable in different lighting conditions. But of course it is more effort to set it up.

Let's say that you already have isolated the dial and know its radius and center. Starting from there the straight forward approach would be:

  • Prepare the image for thresholding:
    • If the image is of low resolution as in our case, scale it up by some reasonable factor
    • If the image is of high resolution, blur it to reduce noise
    • Convert it to grayscale
  • Apply adaptiveThresholding or Canny, in this case use the first one
  • Only keep areas that are of interest:
    • In this case only keep the features in a circular range where the triangle is supposed to be
    • In this case only keep the contour with the largest area
  • Derive the result:
    • In this case just get the centroid of the largest contour

Code:

import cv2
import numpy as np


# read image, scale it up by some factor and apply adaptive thresholding
img = cv2.imread("img_red.jpg")
h, w, _ = img.shape
f = 8
img = cv2.resize(img, (w * f, h * f))
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
thresh = cv2.adaptiveThreshold(gray, 255,
                               cv2.cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
                               cv2.THRESH_BINARY_INV, 71, 5)
cv2.imwrite("thresh.png", thresh)

# only examine circle where the triangle is supposed to be
mask = np.zeros_like(thresh)
cv2.circle(mask, (int(w * f / 2), int(h * f / 2)), int(w * f / 3), 255, int(w * f / 6))
thresh = cv2.bitwise_and(thresh, mask)
cv2.imwrite("thresh_mask.png", thresh)

# get contours, derive contour with largest area and get centroid
contours, _ = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

if contours:
    m = max([(c, cv2.contourArea(c)) for c in contours], key=lambda i: i[1])[0]

    M = cv2.moments(m)

    if M['m00'] > 0:
        x = round(M['m10'] / M['m00'])
        y = round(M['m01'] / M['m00'])

        # draw small red circle at centroid
        cv2.circle(img, (x, y), 2 * f, (0, 0, 255), f)

cv2.imwrite("out.png", img)

Results:

results

Sign up to request clarification or add additional context in comments.

12 Comments

So the image that I'm actually manipulating, where it is just the dial, is about 60 by 60 pixels. So while the thresholding works its not as effective. The main problem is still just being able to find a point on that triangle, which thresholding doesn't even fully outline most of the time.
@Will Can you post the image you're actually manipulating?
@Will Thank you! I have updated my answer and hope that I got you right, this time.
@Will Please share the images that run into problems.
@Will Thank you for sharing more examples! I have updated my answer, accordingly. The main improvement I added is scaling up the low resolution images to get better thresholding results.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.