Canny Edge detector C++

43 Views Asked by At

Is anyone here familiar with implementing canny from scratch in C++? I'm having trouble with the output image of the filter. I'm using Qt to create app. I applied Sobel Sobel, Canny. I think it's an issue related to format of final edges or something, but I can't figure it out.

Sobel is working Fine, but Canny is showing the filtered image multiple times stacked together.

Canny From OpenCV Canny from scratch

void QtWidgetsApplication2::applyCannyFilter()
{
    if (!img_detection.empty()) {
        // Define Canny thresholds (adjust as needed)
        int lowThreshold = 5;
        int highThreshold = 20;

        // Convert image to grayscale if it's not already
        cv::Mat grayImage;
        cv::cvtColor(img_detection, grayImage, cv::COLOR_BGR2GRAY);

        // Apply Canny edge detection using custom function
        cv::Mat edges;
        cv::Canny(grayImage, edges, lowThreshold, highThreshold);

        // Convert the output to QImage for display
        QImage qImage(edges.data, edges.cols, edges.rows, edges.step, QImage::Format_Grayscale8);
        if (qImage.isNull()) {
            std::cerr << "Error: Unable to convert image to QImage." << std::endl;
            return;
        }

        // Convert grayscale to RGB for display
        cv::Mat displayImage;
        cv::cvtColor(edges, displayImage, cv::COLOR_GRAY2RGB);

        // Display the image in the specified QLabel
        QPixmap pixmap = QPixmap::fromImage(QImage(displayImage.data, displayImage.cols, displayImage.rows, displayImage.step, QImage::Format_RGB888));
        ui->outputLabel_3->setPixmap(pixmap.scaled(ui->outputLabel_3->size(), Qt::KeepAspectRatio));
        ui->outputLabel_3->setAlignment(Qt::AlignCenter);
    }
    else {
        std::cerr << "Error: No image loaded." << std::endl;
    }
}
void applyCanny(const cv::Mat& input, cv::Mat& output, int lowThreshold, int highThreshold) {
    // Apply Sobel to get gradient images
    cv::Mat gradX, gradY;
    cv::Mat out;
    std::tie(gradX, gradY) = applySobel(input,out);

    // Calculate gradient magnitude and direction
    cv::Mat gradMagnitude = cv::Mat::zeros(input.size(), CV_32F);
    cv::Mat gradDirection = cv::Mat::zeros(input.size(), CV_32F);

    for (int i = 0; i < input.rows; ++i) {
        for (int j = 0; j < input.cols; ++j) {
            float gx = gradX.at<float>(i, j);
            float gy = gradY.at<float>(i, j);
            gradMagnitude.at<float>(i, j) = std::sqrt(gx * gx + gy * gy);

            gradDirection.at<float>(i, j) = std::atan2(gy, gx) * 180 / CV_PI;
            if (gradDirection.at<float>(i, j) < 0) {
                gradDirection.at<float>(i, j) += 180; // Convert negative angles to positive
            }
        }
    }

    // Non-maximum Suppression
    cv::Mat nonMaxSuppressed = cv::Mat::zeros(gradMagnitude.size(), CV_8UC1);
    for (int i = 1; i < gradMagnitude.rows - 1; ++i) {
        for (int j = 1; j < gradMagnitude.cols - 1; ++j) {
            float angle = gradDirection.at<float>(i, j);
            float mag1, mag2;

            // Horizontal edge
            if ((angle >= -22.5 && angle < 22.5) || (angle >= 157.5 && angle <= 180) || (angle >= 0 && angle < 22.5)) {
                mag1 = gradMagnitude.at<float>(i, j - 1);
                mag2 = gradMagnitude.at<float>(i, j + 1);
            }
            // Diagonal edge (top-left to bottom-right)
            else if ((angle >= 22.5 && angle < 67.5) || (angle >= 180 && angle < 202.5)) {
                mag1 = gradMagnitude.at<float>(i - 1, j - 1);
                mag2 = gradMagnitude.at<float>(i + 1, j + 1);
            }
            // Vertical edge
            else if ((angle >= 67.5 && angle < 112.5) || (angle >= 202.5 && angle < 247.5)) {
                mag1 = gradMagnitude.at<float>(i - 1, j);
                mag2 = gradMagnitude.at<float>(i + 1, j);
            }
            // Diagonal edge (bottom-left to top-right)
            else {
                mag1 = gradMagnitude.at<float>(i + 1, j - 1);
                mag2 = gradMagnitude.at<float>(i - 1, j + 1);
            }

            // Perform non-maximum suppression
            if (gradMagnitude.at<float>(i, j) >= mag1 && gradMagnitude.at<float>(i, j) >= mag2) {
                nonMaxSuppressed.at<uchar>(i, j) = 255;
            }
        }
    }

    // Double Thresholding
    cv::Mat edges = cv::Mat::zeros(nonMaxSuppressed.size(), CV_8UC1);
    for (int i = 0; i < nonMaxSuppressed.rows; ++i) {
        for (int j = 0; j < nonMaxSuppressed.cols; ++j) {
            if (nonMaxSuppressed.at<uchar>(i, j) >= highThreshold) {
                edges.at<uchar>(i, j) = 255;
            }
            else if (nonMaxSuppressed.at<uchar>(i, j) >= lowThreshold && nonMaxSuppressed.at<uchar>(i, j) < highThreshold) {
                // Check 8-connected neighbors
                if (nonMaxSuppressed.at<uchar>(i-1, j-1) >= highThreshold ||
                    nonMaxSuppressed.at<uchar>(i-1, j) >= highThreshold ||
                    nonMaxSuppressed.at<uchar>(i-1, j+1) >= highThreshold ||
                    nonMaxSuppressed.at<uchar>(i, j-1) >= highThreshold ||
                    nonMaxSuppressed.at<uchar>(i, j+1) >= highThreshold ||
                    nonMaxSuppressed.at<uchar>(i+1, j-1) >= highThreshold ||
                    nonMaxSuppressed.at<uchar>(i+1, j) >= highThreshold ||
                    nonMaxSuppressed.at<uchar>(i+1, j+1) >= highThreshold) {
                    edges.at<uchar>(i, j) = 255;
                }
            }
        }
    }
    // Convert edges to CV_8U format
    edges.convertTo(edges, CV_8U);
    output = edges;
}

0

There are 0 best solutions below