OpenCV-Hinweise (9): Häufig verwendete Kantenerkennungsoperatoren – Roberts, Prewitt, Sobel

Bevor wir mit diesem Artikel beginnen, wollen wir zunächst das Konzept der Operatoren verstehen.

Operator im Englischen ist Operator, eine Abbildung vom Funktionsraum zum Funktionsraum O:X→X. Operatoren im weitesten Sinne können auf jeden Raum verallgemeinert werden.

Funktionen sind Abbildungen von Zahlen auf Zahlen.

Eine Funktion ist eine Abbildung von Funktionen auf Zahlen.

Operatoren sind Abbildungen von Funktionen auf Funktionen.

Operatoren entsprechen weder Funktionen noch Algorithmen. Algorithmus ist ein umfassenderes Konzept, das Operatoren umfasst.

Teil 11. Roberts-Operator

Wir wissen, dass die L1-Norm verwendet wird, um die Größe des Gradienten anzunähern:

In,

In x-Richtung handelt es sich gemäß der partiellen Ableitungsformel tatsächlich um die Subtraktion der Werte zweier benachbarter Pixel. Dasselbe gilt auch für die y-Richtung. Daher kann der folgende Operator erhalten werden.

24a83f231c07ef2874138519558abc1d.jpeg
Vertikale und horizontale Farbverläufe des Bildes.png

Ebenso gibt es diagonale Richtungen . Für diagonale Farbverläufe lauten die Formeln und Operatoren wie folgt:

Roberts -Faltungskern:

38d2b8e7060c65446e3d510bce54fd0e.jpeg
Roberts Faltungskernel.png

Wir können eine Kantenerkennung basierend auf dem Roberts-Operator implementieren

#include <opencv2/opencv.hpp>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
using namespace std;
using namespace cv;

void roberts(Mat& input, Mat& output, Mat& kernel_x, Mat& kernel_y)
{
    int height = input.rows;
    int width = input.cols;

    int height_x = kernel_x.rows;
    int width_x = kernel_x.cols;

    int height_y = kernel_y.rows;
    int width_y = kernel_y.cols;

    for (int row = 1; row < height - 1; row++)
    {
        for (int col = 1; col < width - 1; col++)
        {
            float G_X = 0;
            for (int h = 0; h < height_x; h++)
            {
                for (int w = 0; w < width_x; w++)
                {
                    G_X += input.at<uchar>(row + h, col + w) * kernel_x.at<float>(h, w);
                }
            }

            float G_Y = 0;
            for (int h = 0; h < height_y; h++)
            {
                for (int w = 0; w < width_y; w++)
                {
                    G_Y += input.at<uchar>(row + h, col + w) * kernel_y.at<float>(h, w);
                }
            }

            output.at<uchar>(row, col) = saturate_cast<uchar>(cv::abs(G_X) + cv::abs(G_Y));
        }
    }
}

int main(int argc,char *argv[])
{

    Mat src = imread(".../street.jpg");
    imshow("src",src);

    Mat gray;
    cv::cvtColor(src, gray, COLOR_BGR2GRAY);

    Mat kernelRoX = (cv::Mat_<float>(2,2) << -1,0,0,1);
    Mat kernelRoY = (cv::Mat_<float>(2,2) << 0,-1,1,0);

    Mat dst;
    dst.create(gray.rows,gray.cols,gray.type());
    roberts(gray, dst, kernelRoX, kernelRoY);

    imshow("Roberts",dst);
    waitKey(0);
    return 0;
}
6244459e2870d499772b2eaa003a8deb.jpeg
Angepasste Implementierung von Roberts Edge Detection.png

Sie können auch die benutzerdefinierte Filterfunktion filter2D() von OpenCV verwenden , um die Roberts-Kantenerkennung zu implementieren:

int main(int argc,char *argv[])
{
    Mat src = imread(".../street.jpg");
    imshow("src",src);

    Mat gray;
    cv::cvtColor(src, gray, COLOR_BGR2GRAY);

    Mat kernelRoX = (cv::Mat_<float>(2,2) << -1,0,0,1);
    Mat kernelRoY = (cv::Mat_<float>(2,2) << 0,-1,1,0);

    Mat dstRoX;
    Mat dstRoY;

    cv::filter2D(gray,dstRoX,-1,kernelRoX);
    cv::filter2D(gray,dstRoY,-1,kernelRoY);
    imshow("Roberts X", dstRoX);
    imshow("Roberts Y", dstRoY);
    dstRoX = cv::abs(dstRoX);
    dstRoY = cv::abs(dstRoY);

    Mat dst;
    add(dstRoX,dstRoY,dst);
    imshow("Roberts", dst);

    waitKey(0);
    return 0;
}
e5d6b0f270f3089786da23086afb61d2.jpeg
Roberts x- und y-Richtung.png
e20350fb7cd778bf78a23ffbd57d1a1b.jpeg
roberts.png

Teil 22. Prewitt-Operator

Im 3×3-Bereich in der Abbildung unten verwendet der Roberts-Operator die Summe, um die Diagonaldifferenz zu implementieren.

40ab590c78bdcb4224ef2c8e4c4647b1.jpeg
3*3 Vorlage.png

Während Kernel der Größe 2×2 vom Konzept her einfach sind, sind sie bei der Berechnung von Kantenrichtungen nicht so nützlich wie zentrosymmetrische Kernel, die eine Mindestgröße von 3×3 haben.

Die Designidee des Prewitt-Operators: Die benachbarten Punkte des realen Grenzpunkts in horizontaler und vertikaler Richtung sollten ebenfalls Grenzpunkte sein. Daher wird die Kantenerkennung durch die Verwendung eines größeren Kantenerkennungsfilters und die Berücksichtigung weiterer umgebender Punkte effizienter . präzise.

Prewitt- Faltungskern:

0b53749d7610fcfd3de5eeec3bd9c4c7.jpeg
Prewitt Faltungskernel.png

Der Prewitt-Operator lautet wie folgt:

#include <opencv2/opencv.hpp>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
using namespace std;
using namespace cv;

void prewitt(Mat& input, Mat& output, Mat& kernel_x, Mat& kernel_y)
{
    int height = input.rows;
    int width = input.cols;

    int height_x = kernel_x.rows;
    int width_x = kernel_x.cols;

    int height_y = kernel_y.rows;
    int width_y = kernel_y.cols;

    for (int row = 1; row < height - 1; row++)
    {
        for (int col = 1; col < width - 1; col++)
        {
            float G_X = 0;
            for (int h = 0; h < height_x; h++)
            {
                for (int w = 0; w < width_x; w++)
                {
                    G_X += input.at<uchar>(row + h - 1, col + w - 1) * kernel_x.at<float>(h, w);
                }
            }

            float G_Y = 0;
            for (int h = 0; h < height_y; h++)
            {
                for (int w = 0; w < width_y; w++)
                {
                    G_Y += input.at<uchar>(row + h - 1, col + w - 1) * kernel_y.at<float>(h, w);
                }
            }

            output.at<uchar>(row, col) = saturate_cast<uchar>(cv::abs(G_X) + cv::abs(G_Y));
        }
    }
}

int main(int argc,char *argv[])
{
    Mat src = imread(".../street.jpg");
    imshow("src",src);

    Mat gray;
    cv::cvtColor(src, gray, COLOR_BGR2GRAY);

    Mat kernelPrewittX = (cv::Mat_<float>(3,3) << -1,0,1,-1,0,1,-1,0,1);
    Mat kernelPrewittY = (cv::Mat_<float>(3,3) << -1,-1,-1,0,0,0,1,1,1);

    Mat dst;
    dst.create(gray.rows,gray.cols,gray.type());
    prewitt(gray, dst, kernelPrewittX, kernelPrewittY);
    imshow("Prewitt", dst);

    waitKey(0);
    return 0;
}
2f50418c2d10dba43af36ee98864a6a5.jpeg
Benutzerdefinierte implementierte Prewitt-Kantenerkennung.png

Verwenden Sie die benutzerdefinierte Filterfunktion filter2D() von OpenCV, um die Prewitt-Kantenerkennung zu implementieren:

int main(int argc,char *argv[])
{
    Mat src = imread(".../street.jpg");
    imshow("src",src);

    Mat gray;
    cv::cvtColor(src, gray, COLOR_BGR2GRAY);

    Mat kernelPrewittX = (cv::Mat_<float>(3,3) << -1,0,1,-1,0,1,-1,0,1);
    Mat kernelPrewittY = (cv::Mat_<float>(3,3) << -1,-1,-1,0,0,0,1,1,1);

    Mat dstPrewittX;
    Mat dstPrewittY;

    cv::filter2D(gray,dstPrewittX,-1,kernelPrewittX);
    cv::filter2D(gray,dstPrewittY,-1,kernelPrewittY);
    imshow("Prewitt X", dstPrewittX);
    imshow("Prewitt Y", dstPrewittY);
    dstPrewittX = cv::abs(dstPrewittX);
    dstPrewittY = cv::abs(dstPrewittY);

    Mat dst;
    add(dstPrewittX,dstPrewittY,dst);
    imshow("Prewitt", dst);

    waitKey(0);
    return 0;
}

Prewitt X erkennt vertikale Grenzen und Prewitt Y erkennt horizontale Grenzen.

2b8591cbb72ca96e54744d25e03cb6e1.jpeg
Prewitt x- und y-Richtungen

Die folgende Abbildung zeigt den gemeinsamen Gradienten.

a5799e1881f08912f80d5ad45432bdb8.jpeg
prewitt.png

Teil 33. Sobel-Operator

Der Roberts-Operator bestimmt Kantenpunkte basierend auf Gradienten in beiden diagonalen Richtungen, und der Prewitt-Operator bestimmt Kantenpunkte basierend auf Gradienten in horizontaler und vertikaler Richtung.

Oben haben wir diese beiden Arten der Kantenerkennung mithilfe der Funktion cv::filter2D() implementiert, die beide die Auswirkungen der Kantenerkennung in zwei Richtungen zeigten. Wir haben festgestellt, dass die Kantenerkennungseffekte von Farbverläufen in verschiedenen Richtungen ihre eigenen Eigenschaften haben .

Durch die Fusion von Farbverläufen in mehreren Richtungen kann der Kantenerkennungseffekt effektiv verbessert werden. Der Sobel-Operator berücksichtigt horizontale, vertikale und zwei diagonale Richtungen, insgesamt also 4 Richtungspaare der gewichteten Gradientensummierung.

e9a38a142bb9b9da32bbc8145aa3a324.jpeg
Sobel-Gradient in alle Richtungen.png

Der Autor von Sobel definierte die Größe des Gradientenvektors g in einer bestimmten Nachbarschaftsrichtung als:

Pixel-Graustufendifferenz-Pixelabstand

Unter diesen wird der Pixelabstand mithilfe der Manhattan-Distanz berechnet .

Der Manhattan-Abstand wurde bereits im sechsten Artikel eingeführt. Dies bedeutet, dass die Punkte, die von Pixel p bis Pixel q verschoben werden können, jedes Mal in der 4- Nachbarschaft des aktuellen Pixels liegen müssen. Nachdem Sie Schritt für Schritt zum Punkt q gegangen sind, entspricht die Gesamtzahl der durchlaufenen Pixel der Manhattan-Entfernung.

Die Richtung des Vektors g kann durch den Einheitsvektor der jeweiligen Nachbarschaft des zentralen Pixels z5 angegeben werden. Die Nachbarschaft erscheint hier symmetrisch, also vier Richtungspaare: (z1, z9), (z2, z8), (z3 , z7) ,(z6,z4). Durch Berechnen der Summe der Gradientenvektoren entlang der vier Richtungen kann die durchschnittliche Gradientenschätzung des Pixels z5 erhalten werden .

Die vier Einheitsvektoren [1, 1], [-1, 1], [0, 1], [1, 0] in der Formel steuern die Richtung der Differenz, und die Koeffizienten 1/4 und 1/2 sind die inverse Distanzgewichte. Beispielsweise beträgt der Manhattan-Abstand von z1 bis z9 4 und der Manhattan-Abstand von z2 bis z8 2.

Für die obige Formel wird G mit einem Skalierungsfaktor von 4 multipliziert, um Multiplikations- und Divisionsberechnungen mit Dezimalzahlen zu vermeiden

Es lässt sich ermitteln, dass der Sobel-Operator wie folgt lautet:

Sobel -Faltungskern:

3159de7284f871c4b508b097b0b5d83e.jpeg
Sobel Faltungskernel.png
#include <opencv2/opencv.hpp>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
using namespace std;

using namespace cv;

void sobel(Mat& input, Mat& output, Mat& kernel_x, Mat& kernel_y)
{
    int height = input.rows;
    int width = input.cols;

    int height_x = kernel_x.rows;
    int width_x = kernel_x.cols;

    int height_y = kernel_y.rows;
    int width_y = kernel_y.cols;

    for (int row = 1; row < height - 1; row++)
    {
        for (int col = 1; col < width - 1; col++)
        {
            float G_X = 0;
            for (int h = 0; h < height_x; h++)
            {
                for (int w = 0; w < width_x; w++)
                {
                    G_X += input.at<uchar>(row + h - 1, col + w - 1) * kernel_x.at<float>(h, w);
                }
            }

            float G_Y = 0;
            for (int h = 0; h < height_y; h++)
            {
                for (int w = 0; w < width_y; w++)
                {
                    G_Y += input.at<uchar>(row + h - 1, col + w - 1) * kernel_y.at<float>(h, w);
                }
            }

            output.at<uchar>(row, col) = saturate_cast<uchar>(cv::abs(G_X) + cv::abs(G_Y));
        }
    }
}

int main(int argc,char *argv[])
{

    Mat src = imread(".../street.jpg");
    imshow("src",src);

    Mat gray;
    cv::cvtColor(src, gray, COLOR_BGR2GRAY);

    Mat kernelSobelX = (cv::Mat_<float>(3,3) << -1,0,1,-2,0,2,-1,0,1);
    Mat kernelSobelY = (cv::Mat_<float>(3,3) << -1,-2,-1,0,0,0,1,2,1);

    Mat dst;
    dst.create(gray.rows,gray.cols,gray.type());
    sobel(gray, dst, kernelSobelX, kernelSobelY);
    imshow("Sobel", dst);

    waitKey(0);
    return 0;
}
8dee28502649386d80a5ba852e9cae54.jpeg
Angepasste Implementierung von Sobel Edge Detection.png

Verwenden Sie die OpenCV-eigene Sobel()-Funktion, um die Kantenerkennung zu implementieren

int main(int argc,char *argv[])
{

    Mat src = imread(".../street.jpg");
    imshow("src",src);

    Mat gray;
    cv::cvtColor(src, gray, COLOR_BGR2GRAY);

    Mat dstSobelX;
    Mat dstSobelY;

    Sobel(gray, dstSobelX, CV_16S, 1, 0, 3);
    Sobel(gray, dstSobelY, CV_16S, 0, 1, 3);
    convertScaleAbs(dstSobelX, dstSobelX);
    convertScaleAbs(dstSobelY, dstSobelY);

    imshow("Sobel X", dstSobelX);
    imshow("Sobel Y", dstSobelY);

    Mat dst;
    add(dstSobelX,dstSobelX,dst);
    imshow("Sobel", dst);

    waitKey(0);
    return 0;
}
b89bc2c7b61e2c6d9a1ea6c1d07a5d2a.jpeg
sobel x- und y-Richtung.png
ecc0646d592f5d9d31f3762177a69040.jpeg
sobel.png

Die von OpenCV bereitgestellte Sobel()-Funktion erläutert kurz die Bedeutung mehrerer Parameter

void Sobel( InputArray src, OutputArray dst, int ddepth,
           int dx, int dy, int ksize = 3,
           double scale = 1, double delta = 0,
           int borderType = BORDER_DEFAULT );

Der dritte Parameter dtiefe: repräsentiert den Datentyp des Ausgabegradienten

  • Wenn src. Depth() = CV_8U, dann d Depth = -1/CV_16S/CV_32F/CV_64F

  • Wenn src. Depth() = CV_16U/CV_16S, dann ist d Depth = -1/CV_32F/CV_64F

  • Wenn src. Depth() = CV_32F, dann d Depth = -1/CV_32F/CV_64F

  • Wenn src. Depth() = CV_64F, dann d Depth = -1/CV_64F

Der vierte Parameter dx: die Reihenfolge der Ableitung in Richtung der x-Achse. dx=1, dy=0 bedeutet die Berechnung des Gradienten in x-Richtung.

Der fünfte Parameter dy: die Reihenfolge der Ableitung in Richtung der y-Achse. dx=0, dy=1 bedeutet die Berechnung des Gradienten in y-Richtung.

Der sechste Parameter ksize: Die Größe des Sobel-Faltungskerns. Verwenden Sie 3, 5, 7, 9, 11 usw.

Teil 44. Zusammenfassung

Bei der tatsächlichen Bildsegmentierung verwenden wir häufig nur Ableitungen erster und zweiter Ordnung, die beide ihre eigenen Vorteile haben. Roberts-, Prewitt- und Sobel-Operatoren sind abgeleitete Kantenoperatoren erster Ordnung. Sie führen eine Faltungssummenoperation mit jedem Pixel des Bildes durch einen Faltungskern aus und wählen dann einen geeigneten Schwellenwert aus, um die Kante des Bildes zu extrahieren. In diesem Artikel werden diese Operatoren verwendet, um die Kantenerkennung für dasselbe Bild durchzuführen, und Sie können verschiedene Effekte sehen. Nachdem wir alle häufig verwendeten Operatoren vorgestellt haben, werden wir sie zusammenfassen.

Darüber hinaus haben wir bereits den Laplace-Operator eingeführt, bei dem es sich um einen Ableitungsoperator zweiter Ordnung handelt. Spätere Artikel werden weiterhin den Kantenoperator der Ableitung zweiter Ordnung vorstellen.

[ Java- und Android-Technologie-Stack] Öffentliches Konto

Achten Sie auf Java/Kotlin-Server, Desktop, Android, maschinelles Lernen und clientseitige Intelligenz

Für weitere spannende Inhalte achten Sie bitte auf:

Supongo que te gusta

Origin blog.csdn.net/SLFq6OF5O7aH/article/details/134778378
Recomendado
Clasificación