5.20. Regressie en gelijkenis

Twee andere metingen op de Image-klasse vatten de afbeelding samen als iets anders dan een verdeling van pixelwaarden. Lineaire regressie van gedrempelde pixels geeft een toepassing een lijn waarop ze kan reageren – de klassieke invoer voor een lijnvolgende robot. Gelijkenismeting geeft een toepassing een enkel getal dat beschrijft hoe gelijk twee afbeeldingen zijn – de natuurlijke invoer voor een golden-image-regressietest of een grof-veranderingsdetector.

5.20.1. Lineaire regressie

Wanneer de voorgrondpixels van een afbeelding toevallig een lijn vormen over het frame – de tape op een baan die een robot volgt, de lijn van een horizon, de rand van een weg of een gang – wil de toepassing meestal niet elke afzonderlijke voorgrondpixel. Ze wil de best passende lijn door ze allemaal, geparameteriseerd zodat ze kan bepalen hoe de lijn is georiënteerd en waar die het frame kruist.

get_regression() doet die fit. Ze neemt dezelfde drempelwaarde-tupelvorm die binary() en find_blobs() gebruiken, identificeert elke pixel die met de drempelwaarde overeenkomt, en geeft een enkel line-resultaat terug dat de best passende lijn door die pixels beschrijft:

line = img.get_regression([(0, 60)])
if line:
    img.draw_line((line.x1(), line.y1(),
                   line.x2(), line.y2()),
                  color=(255, 0, 0))

De fit is Theil-Sen-lineaire regressie – een robuuste methode die uitschieters beter tolereert dan de meer bekende kleinste-kwadratenfit. Een klein handjevol pixels ver van de werkelijke lijn trekt het resultaat niet scheef zoals dat bij kleinste kwadraten zou gebeuren, wat overeenkomt met de ruisende-voorgrondrealiteit van een echte drempelwaarde-uitvoer.

Het line-resultaat draagt de eindpunten geknipt tot de afbeeldingsrechthoek (x1, y1, x2, y2), de lijnlengte en magnitude (length, magnitude), en de geometrische beschrijving van de lijn in polaire vorm (theta, rho) – de hoek van de lijn ten opzichte van horizontaal en de loodrechte afstand tot de oorsprong. De polaire vorm is wat een regellus meestal wil: theta vertelt de robot welke kant de lijn op helt, rho vertelt hem waar de lijn de afbeelding kruist, en een terugkoppellus op die twee houdt de robot gecentreerd op de lijn.

Een handvol sleutelwoordargumenten stemmen de robuustheid en de kosten af. x_stride en y_stride slaan pixels over tijdens de fit – grotere stappen maken de regressie goedkoper ten koste van het passen van minder pixels. area_threshold en pixels_threshold verwerpen lijnen die niet genoeg overeenkomende pixels achter zich hebben. target_size herschaalt de invoer naar een kleinere grootte vóór het passen – de regressie draait sneller op een surrogaat van 80 bij 60 van de afbeelding zonder veel verlies in nauwkeurigheid van de lijnrichting.

Als er geen aanvaardbare lijn kon worden gepast – als de drempelwaarde geen pixels overeenkwam, of een patroon overeenkwam dat er niet als een lijn uitziet – geeft de methode None terug. Echte lijnvolgcode beschermt elke get_regression()-aanroep met een None-controle voordat ze de attributen van de lijn benadert.

5.20.2. Afbeeldingsgelijkenis

Een ander soort meting: in plaats van te vragen “wat bevat de afbeelding?”, vraag “hoe gelijk zijn deze twee afbeeldingen?”. De bewerking om naar te grijpen is get_similarity(), die de Structural Similarity Index (SSIM) berekent tussen de bronafbeelding en een referentieafbeelding.

s = img.get_similarity(reference)
print(s.mean, s.stdev)

SSIM is de standaardmaat voor afbeeldingsgelijkenis die in de hele beeldverwerking wordt gebruikt omdat hij zich gedraagt zoals de menselijke intuïtie over gelijkenis zich gedraagt – een kleine verschuiving of een kleine helderheidsverandering verlaagt de score licht, terwijl een grote structurele verandering (ontbrekend object, andere scène) hem dramatisch verlaagt. De score loopt van -1 tot +1: +1 betekent dat de twee afbeeldingen identiek zijn, 0 betekent dat ze ongerelateerd zijn, en -1 betekent dat ze structureel tegengesteld zijn. Een teruggegeven similarity-object stelt de gemiddelde SSIM over de afbeelding beschikbaar, plus de standaarddeviatie, min en max van de scores per tegel.

Voor het soort vergelijking waarbij een klein getal beter is dan een groot getal – een regressietest die nul zou moeten rapporteren bij “er is niets veranderd” en zou moeten stijgen naarmate veranderingen zich opstapelen – geeft de vlag dssim=True de structurele ongelijkenis terug: de gemiddelde SSIM afgetrokken van 1, zodat de retourwaarde 0.0 is voor identieke afbeeldingen en stijgt naarmate ze verschillen.

5.20.3. Toepassingen voor SSIM

De twee veelvoorkomende toepassingen:

Golden-image-regressietesten. Een testframework legt een referentieframe vast onder bekende goede omstandigheden en slaat het op als de golden image. Latere testruns leggen vast onder dezelfde omstandigheden en vergelijken met de golden image met behulp van SSIM. Een score boven een bepaalde drempelwaarde (0.95 of 0.98 afhankelijk van de tolerantie) is een geslaagde test; eronder is een mislukking. Het testframework hoeft niet te weten wat er is veranderd – de SSIM-score is het signaal.

Grove veranderingsdetectie. Een toepassing die een grovere versie van framedifferentiatie wil – één die kleine helderheidsveranderingen negeert maar reageert op grote structurele veranderingen – kan SSIM gebruiken ten opzichte van een referentieframe in plaats van de per-pixel difference() gevolgd door een drempelwaarde. SSIM is minder gevoelig voor lichtafdrift dan per-pixel-differentiatie, wat het de betere keuze maakt wanneer het doel is om te detecteren dat “de scène er wezenlijk anders uitziet” in plaats van dat “een individuele pixel is veranderd.”

Beide toepassingen gebruiken dezelfde aanroep – img.get_similarity(reference) – en triggeren op een drempelwaarde van de teruggegeven score. Het verschil is alleen of de drempelwaarde hoog is (regressietest, op zoek naar een bijna-identieke overeenkomst) of laag (veranderingsdetectie, op zoek naar een grote structurele verandering).

5.20.4. De transformeer-en-vergelijk-vorm

Een nuttige subtiliteit: get_similarity() accepteert dezelfde x-, y-, x_scale-, y_scale-, roi-, rgb_channel-, alpha-, color_palette-, alpha_palette-, hint- en transform-parameters als draw_image(). De referentieafbeelding wordt door die parameters gepositioneerd, geschaald en getransformeerd voordat de SSIM-vergelijking draait.

Dat betekent dat een toepassing kan vragen “hoe gelijk is deze scène aan een referentieframe na een bekende verplaatsing / rotatie / schaal” zonder een vooraf getransformeerde referentieafbeelding voor te bereiden. Het is de goedkope manier om een tracker te bouwen die een parameterruimte doorzoekt en rapporteert welke transformatie van de referentie het best overeenkomt met het huidige frame.