gpt4 book ai didi

c++ - 没有缓冲区的 Sobel 边缘检测

转载 作者:行者123 更新时间:2023-11-28 02:27:05 29 4
gpt4 key购买 nike

对于嵌入式设计,我试图在不使用缓冲器的情况下在板上实现索贝尔边缘检测。即我直接从屏幕上阅读和写作。但是,我可以存储大约一两个图像宽度的数据以供以后引用。这是由于董事会规定的限制。但是我陷入了一些问题。无论我尝试使用 sobel 还是其他边缘检测算法,我收到的都是噪音。代码如下,大家有什么建议吗

版本 1

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;
}

版本 2

/**
* 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

// 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);
}
}
}

最佳答案

对于版本 1,分配 2 个缓冲区(只需使用 bufferbufT)后,创建 2 个指针指向当前行和上一行,如下所示:

uint16_t *currentRow = buffer;
uint16_t *prevRow = bufT;

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

pixel16 pix(newPixel[0], newPixel[1], newPixel[2]);
currentRow[X] = packColour(pix).packed565;

因为 Sobel 过滤器从前一行读取,所以您不能覆盖该行,直到您完成计算其后一行的过滤值。因此,在循环的末尾,也就是您当前正在调用 paintRow() 的位置,绘制上一行(如果存在),然后交换缓冲区,以便当前成为上一个,而上一个成为新的当前行(将在下一次通过循环时被覆盖)。在最后一行,当前行也被绘制,否则它不会被绘制,因为外层循环即将终止。

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;

相同的策略应该适用于其他版本。

关于c++ - 没有缓冲区的 Sobel 边缘检测,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30168074/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com