首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >无缓冲器的Sobel边缘检测

无缓冲器的Sobel边缘检测
EN

Stack Overflow用户
提问于 2015-05-11 12:47:26
回答 1查看 585关注 0票数 0

对于嵌入式设计,我尝试在没有使用缓冲区的情况下在板上实现sobel的边缘检测。也就是说,我直接从屏幕上读和写。不过,我可以存储大约一个或两个imge宽度的数据,以供以后参考。这是由于董事会规定的限制。然而,我陷入了一些问题。无论我是否尝试做sobel或其他边缘检测算法,我所收到的都是噪声。代码在下面,有人有什么建议吗?

版本1

代码语言:javascript
复制
void sobelEdgeDetection2() {
    int GX[3][3];
    int GY[3][3];

    int sumX[3];
    int sumY[3];
    int SUM[3];
    int piX = 0;
    int piY = 0;
    //uint8_t R, G, B = 0;
    int I, J = 0;

    //UnpackedColour pixVal;
    uint16_t *buffer;
    // allocate space for even scan lines and odd scan lines
    buffer = new uint16_t[_gl->getWidth()];
    //buffer for previous line
    uint16_t *bufT;
    // allocate space for even scan lines and odd scan lines
    bufT = new uint16_t[_gl->getWidth()];

    // Masks //////////////////////////////////////
    //X//
    GX[0][0] = -1;
    GX[0][1] = 0;
    GX[0][2] = 1;
    GX[1][0] = -2;
    GX[1][1] = 0;
    GX[1][2] = 2;
    GX[2][0] = -1;
    GX[2][1] = 0;
    GX[2][2] = 1;
    //Y//
    GY[0][0] = 1;
    GY[0][1] = 2;
    GY[0][2] = 1;
    GY[1][0] = 0;
    GY[1][1] = 0;
    GY[1][2] = 0;
    GY[2][0] = -1;
    GY[2][1] = -2;
    GY[2][2] = -1;

    for (int Y = 0; Y < _gl->getHeight(); Y++) {
        for (int X = 0; X < _gl->getWidth(); X++) {
            sumX[0] = sumX[1] = sumX[2] = 0;
            sumY[0] = sumY[1] = sumY[2] = 0;

            if (Y == 0 || Y == _gl->getHeight() - 1) {
                SUM[0] = SUM[1] = SUM[2] = 0;
            } else if (X == 0 || X == _gl->getWidth() - 1) {
                SUM[0] = SUM[1] = SUM[2] = 0;
            } else {
                for (I = -1; I <= 1; I++) {
                    for (J = -1; J <= 1; J++) {
                        piX = J + X;
                        piY = I + Y;

                        pixel16 pix = getPixel(piX, piY);
                        uint8_t Red = pix.Red;
                        uint8_t Green = pix.Green;
                        uint8_t Blue = pix.Blue;

                        sumX[0] += (Red) * GX[J + 1][I + 1];
                        sumX[1] += (Green) * GX[J + 1][I + 1];
                        sumX[2] += (Blue) * GX[J + 1][I + 1];

                        sumY[0] += (Red) * GY[J + 1][I + 1];
                        sumY[1] += (Green) * GY[J + 1][I + 1];
                        sumY[2] += (Blue) * GY[J + 1][I + 1];
                    }
                }

                SUM[0] = abs(sumX[0]) + abs(sumY[0]);
                SUM[1] = abs(sumX[1]) + abs(sumY[1]);
                SUM[2] = abs(sumX[2]) + abs(sumY[2]);
            }
            if (SUM[0] > 255)
                SUM[0] = 255;
            if (SUM[0] < 0)
                SUM[0] = 0;

            if (SUM[1] > 255)
                SUM[1] = 255;
            if (SUM[1] < 0)
                SUM[1] = 0;

            if (SUM[2] > 255)
                SUM[2] = 255;
            if (SUM[2] < 0)
                SUM[2] = 0;

            int newPixel[3];
            newPixel[0] = (255 - ((unsigned char) (SUM[0])));
            newPixel[1] = (255 - ((unsigned char) (SUM[1])));
            newPixel[2] = (255 - ((unsigned char) (SUM[2])));

            pixel16 pix(newPixel[0], newPixel[1], newPixel[2]);
            buffer[X] = packColour(pix).packed565;
        }
        //Need to move cursor back
        // draw it
        this->paintRow(Point(0, Y), buffer, _gl->getWidth());
    }
    delete[] buffer;
}

Version2

代码语言:javascript
复制
/**
     * https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/image-processing/edge_detection.html
     * 1 Iterate over every pixel in the image
     * 2 Apply the x gradient kernel
     * 3 Apply the y gradient kernel
     * 4 Find the length of the gradient using pythagoras' theorem
     * 5 Normalise the gradient length to the range 0-255
     * 6 Set the pixels to the new values
     */
    void sobelEdgeDetection4() {
        UnpackedColour colour;
        for (int x = 1; x < _gl->getWidth() - 1; x++) {
            for (int y = 1; y < _gl->getHeight() - 1; y++) {
                // initialise Gx and Gy to 0
                int Gx = 0;
                int Gy = 0;
                unsigned int intensity = 0;

                // Left column
                pixel16 pixel = this->getPixel(x - 1, y - 1);
                intensity = pixel.Red + pixel.Green + pixel.Blue;
                Gx += -intensity;
                Gy += -intensity;

                pixel = this->getPixel(x - 1, y);
                intensity = pixel.Red + pixel.Green + pixel.Blue;
                Gx += -2 * intensity;

                pixel = this->getPixel(x - 1, y + 1);
                intensity = pixel.Red + pixel.Green + pixel.Blue;
                Gx += -intensity;
                Gy += +intensity;

                // middle column
                pixel = this->getPixel(x, y - 1);
                intensity = pixel.Red + pixel.Green + pixel.Blue;
                Gy += -2 * intensity;

                pixel = this->getPixel(x, y + 1);
                intensity = pixel.Red + pixel.Green + pixel.Blue;
                Gy += +2 * intensity;

                // right column
                pixel = this->getPixel(x + 1, y - 1);
                intensity = pixel.Red + pixel.Green + pixel.Blue;
                Gx += +intensity;
                Gy += -intensity;

                pixel = this->getPixel(x + 1, y);
                intensity = pixel.Red + pixel.Green + pixel.Blue;
                Gx += +2 * intensity;

                pixel = this->getPixel(x + 1, y + 1);
                intensity = pixel.Red + pixel.Green + pixel.Blue;
                Gx += +intensity;
                Gy += +intensity;

                // calculate the gradient length
                unsigned int length = (unsigned int) sqrt(
                        (float) (Gx * Gx) + (float) (Gy * Gy));

                // normalise the length to 0 to 255
                length = length / 17;

                // draw the pixel on the edge image
                pixel16 pixel2(length,length,length);
                this->setPixel(x, y, pixel2);
            }
        }
    }

第3版

代码语言:javascript
复制
// sobel map for the x axis
    const double _SOBEL_Gx[3][3] = { { -1.0, +0.0, +1.0 }, { -2.0, +0.0, +2.0 },
            { -1.0, +0.0, +1.0 } };
    // sobel map for the y axis
    const double _SOBEL_Gy[3][3] = { { +1.0, +2.0, +1.0 }, { +0.0, +0.0, +0.0 },
            { -1.0, -2.0, -1.0 } };
double get_sobel_gradient(int width, int height, int x, int y) {
        double sobel_gradient_x = 0, sobel_gradient_y = 0;
        int mx = 0, my = 0, sx = 0, sy = 0;

        for (mx = x; mx < x + 3; mx++) {
            sy = 0;
            for (my = y; my < y + 3; my++) {
                if (mx < width && my < height) {
                    //int r, g, b, idx;
                    int idx = (mx + width * my) * 3;

                    pixel16 pixVal = this->getPixel(idx);

                    //r = pixVal.Red;
                    //g = pixVal.Green;
                    //b = pixVal.Blue;
                    UnpackedColour col = this->packColour(pixVal);
                    sobel_gradient_x += col.packed565 * _SOBEL_Gx[sx][sy];
                    sobel_gradient_y += col.packed565 * _SOBEL_Gy[sx][sy];
                }
                sy++;
            }
            sx++;
        }

        return abs(sobel_gradient_x) + abs(sobel_gradient_y);
    }

    void sobelEdgeDetection3() {
        double threshold = 50000.0;
        UnpackedColour colour;
        for (int y = 0; y < _gl->getHeight(); y++) {
            for (int x = 0; x < _gl->getWidth(); x++) {
                if (get_sobel_gradient(_gl->getWidth(), _gl->getHeight(), x, y)
                        >= threshold) {
                    colour.packed565 = 0x0000;          //set white
                } else {
                    colour.packed565 = 0xFFFF;          //set black
                }
                this->setPixel(x, y, colour);
            }
        }
    }
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2015-05-11 14:06:59

对于Version 1,在分配两个缓冲区(只使用bufferbufT)之后,创建两个指针来指向当前和以前的行,如下所示:

代码语言:javascript
复制
uint16_t *currentRow = buffer;
uint16_t *prevRow = bufT;

在行循环中,写入currentRow而不是buffer

代码语言:javascript
复制
pixel16 pix(newPixel[0], newPixel[1], newPixel[2]);
currentRow[X] = packColour(pix).packed565;

因为Sobel过滤器是从前一行读取的,所以在计算完之后的行的筛选值之前,不能覆盖一行。因此,在循环的末尾(当前正在调用paintRow() ),绘制前一行(如果存在),然后交换缓冲区,使当前变为前一行,而前一行成为新的当前行(在下一次遍历循环时将被覆盖)。在最后一行中,也会绘制当前行,否则不会绘制,因为外部循环即将终止。

代码语言:javascript
复制
if(Y > 0) // draw the previous row if this is not the first row:
    this->paintRow(Point(0, Y-1), prevRow, _gl->getWidth());
if(Y == _gl->getHeight()-1) // draw the current row if it is the last:
    this->paintRow(Point(0, Y), currentRow, _gl->getWidth());
// swap row pointers:
uint16_t *temp = prevRow;
prevRow = currentRow;
currentRow = temp;

同样的策略也适用于其他版本。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/30168074

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档