plate orientation based on shape

Hi.
I’m new to this field, and I wanted to ask some questions to help my colleagues at work.
I wanted to use an OpenMV camera to orient plates arriving on a conveyor belt in random positions; a mechanical orienter rotates them, and we use a photocell to try to adjust the plate’s orientation.
My idea was to use a camera to read the angle or shape of the plate so that it places the plate in the correct position.
Before investing any money, I wanted to know if this is possible using OpenMV cameras. Thanks, and sorry for my English.

Hi, it is. Can you provide a view from what the camera would likely see so I can suggest an alogirithm?

For this project, I was thinking of using an H7; this decision was made in consultation with the AI.:joy:

Thanks, but, it’s not clear what you are trying to rotate? The plate is round and the same on all sides? So, what needs rotation?

The plates are not identical: one is oval and the other is triangular. I would like to position the oval one with its longest side facing the conveyor belt, and the triangular one with its tip pointing towards the camera. I am attaching two photos showing examples of the plates I use.

The way we orient the plates right now isn’t very reliable; it often makes mistakes because it detects the white too early.

Video

Mmm, this is solvable but challenging.

You can use an image classifier trained via ML, or structure via blob detection.

…

Hmmm, so, using an AI coder here is likely to have good results. What you’ll want to do is apply strong image binarization, then extract the contour of the plate edge. From that, you can fit a curve to the contour points. The curve variables can then be bucketed, and this will tell you which plate you have and its rotation, which can be seen uniquely.

Normally, the above… would be generally a pain to write, but, if you feed that into an AI and tell it to use our numpy ULAB package onboard it can more or less solve it.

Once you have the program, you’ll need to collect the curve info for the plates to get the profiles to compare against, but after you have that data, the AI will be able to make something that’s pretty robust for matching.

The resulting Python code it will write, though, is going to be some very complex curve-fitting functions and heavy mathematics.

I used Gemini to arrive at this solution. It recommends using an OpenMV H7 and inserting this Python code.

import sensor, image, time, pyb, math

# 1. Inizializzazione della Telecamera
sensor.reset()
sensor.set_pixformat(sensor.GRAYSCALE) # Bianco e nero per massima velocità
sensor.set_framesize(sensor.QVGA)      # Risoluzione 320x240
sensor.skip_frames(time = 2000)
sensor.set_auto_gain(False)            # Disattiva regolazioni automatiche per stabilità
sensor.set_auto_whitebal(False)

# 2. Configurazione Pin di Uscita verso il Relè (Pin P0)
relay_pin = pyb.Pin("P0", pyb.Pin.OUT_PP)
relay_pin.low()

# 3. Parametri di Configurazione (Da ritoccare se necessario)
THRESHOLD = (180, 255)     # Soglia luminosità per staccare il piatto bianco dallo sfondo
ANGOLO_OVALE = 90          # Gradi target per il piatto Ovale quando è dritto
ANGOLO_TRIANGOLO = 45      # Gradi target per il piatto Triangolare quando è dritto
TOLLERANZA = 3             # Margine di errore in gradi (+/-)

clock = time.clock()

while(True):
    clock.tick()
    img = sensor.snapshot()

    # Rileva le forme chiare nell'inquadratura (i piatti)
    blobs = img.find_blobs([THRESHOLD], pixels_threshold=3000, area_threshold=3000, merge=True)

    piatto_allineato = False

    if blobs:
        # Prendi l'oggetto più grande presente sul nastro
        piatto = max(blobs, key=lambda b: b.pixels())

        # Disegna il riquadro e il centro a schermo per verifica visiva nell'IDE
        img.draw_rectangle(piatto.rect(), color=255)
        img.draw_cross(piatto.cx(), piatto.cy(), color=255)

        # Calcola l'angolo dell'asse (convertito in gradi 0-180)
        angolo_rilevato = int(math.degrees(piatto.rotation())) % 180
        
        # Rapporto tra larghezza e altezza del riquadro per distinguere i 2 piatti
        rapporto_lati = piatto.w() / float(piatto.h())

        # Distinzione automatica tra Ovale e Triangolo
        if rapporto_lati > 1.15 or rapporto_lati < 0.85:
            # Sagoma allungata -> Piatto OVALE
            angolo_target = ANGOLO_OVALE
            img.draw_string(10, 10, "OVALE", color=255, scale=2)
        else:
            # Sagoma più proporzionata -> Piatto TRIANGOLARE
            angolo_target = ANGOLO_TRIANGOLO
            img.draw_string(10, 10, "TRIANGOLO", color=255, scale=2)

        # Verifica se l'angolo rientra nella tolleranza
        if abs(angolo_rilevato - angolo_target) <= TOLLERANZA:
            piatto_allineato = True

    # 4. Comando al Relè verso l'ingresso I3 del Siemens LOGO!
    if piatto_allineato:
        relay_pin.high() # Chiude il relè -> invia 24V al PLC
        img.draw_string(10, 200, "STOP (ALLINEATO)", color=255, scale=2)
    else:
        relay_pin.low()  # Mantiene il relè aperto```

Please surround your code pastes with code tags. As for what it’s doing, that approach is too simplistic. As you cannot see the whole plate at once it won’t work. The approach I outlines will work given only seeing a partial plate.

Either way, if you just let the AI iterate on the code it will find a solution. We’ll have a version of OpenMV IDE out soon which will be able connect to an auto coder and allow it to program the camera automatically in a month or so.

Sorry about the code. I’ll log in from my PC tomorrow and fix it. I’ll wait for the new version of the IDE and start running some tests with photos.