Sobel.cpp
Description
Qt and GDI+ versions of the Sobel edge detection algorithm.
Requirements
Visual Studio, Qt, GDI+. Tested with Qt 3.4, but should work with Qt 4.x
without too many troubles. CodeProject is a good
place to find articles on using GDI+.
Details
Given image in source place Sobel edges in dest. This is what it looks like:
Copy the code below, or Download a zip.
void ImageManipQt::Sobel
(QImage & source,
QImage & sobelDestination
)
{
int GX[3][3];
int GY[3][3];
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;
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;
int width = source.width();
int height = source.height();
uint blackPixel = qRgb(0, 0, 0);
uchar **jumper = source.jumpTable();
uchar **destJumper = sobelDestination.jumpTable();
int I, J;
long sumX, sumY;
int SUM;
uint rawColour;
for (int y = 0; y < height; ++y)
{
uint *p = (uint *)jumper[y];
uint *dp = (uint *)destJumper[y];
for (int x = 0; x < width; ++x)
{
if ( y == 0 || y >= height-1
|| x == 0 || x >= width-1 )
{
SUM = 0;
}
else
{
sumX = 0;
sumY = 0;
for(I=-1; I<=1; I++)
{
for(J=-1; J<=1; J++)
{
rawColour = *((uint *)jumper[y + J] + x + I);
sumX =
sumX + ((qRed(rawColour) + qGreen(rawColour) + qBlue(rawColour))/3) * GX[I+1][J+1];
sumY =
sumY + ((qRed(rawColour) + qGreen(rawColour) + qBlue(rawColour))/3) * GY[I+1][J+1];
}
}
SUM = abs(sumX) + abs(sumY);
if (SUM > 255)
SUM = 255;
}
*dp = qRgb(SUM, SUM, SUM);
++p;
++dp;
}
}
}
#define SOURCE_PIXEL_PTR(xs,ys) (pPixelSrc + ys*dLineSrc + xs*dPixelSrc)
void ImageManipGDIP::Sobel(Bitmap *source, Bitmap *sobelDestination)
{
int GX[3][3];
int GY[3][3];
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;
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;
const int nPlanes = 4;
Rect rc(0, 0, source->GetWidth(), source->GetHeight());
BitmapData dataSrc;
Status s = source->LockBits(& rc, ImageLockModeRead, PixelFormat32bppARGB, & dataSrc);
if (s == Ok)
{
BitmapData dataDest;
s = sobelDestination->LockBits(& rc, ImageLockModeRead | ImageLockModeWrite,
PixelFormat32bppARGB, & dataDest);
if (s == Ok)
{
BYTE * pStartSrc = (BYTE *) dataSrc.Scan0;
BYTE * pStartDest = (BYTE *) dataDest.Scan0;
UINT nLines = dataDest.Height;
UINT nPixels = dataDest.Width;
UINT dPixelSrc = nPlanes;
UINT dPixelDest = nPlanes;
UINT dLineSrc = dataSrc.Stride;
UINT dLineDest = dataDest.Stride;
BYTE * pLineSrc = pStartSrc;
BYTE * pLineDest = pStartDest;
int SUM;
for (UINT y = 0; y < nLines; y++)
{
BYTE *pPixelSrc = pLineSrc;
BYTE *pPixelDest = pLineDest;
for (UINT x = 0; x < nPixels; x++)
{
if ( y == 0 || y >= nLines-1
|| x == 0 || x >= nPixels-1 )
{
SUM = 0;
}
else
{
long sumX = 0;
long sumY = 0;
for(int I=-1; I<=1; I++)
{
for(int J=-1; J<=1; J++)
{
BYTE *curP = SOURCE_PIXEL_PTR(I,J);
BYTE b = *curP;
BYTE g = *(curP+1);
BYTE r = *(curP+2);
sumX += ((r+g+b)/3) * GX[I+1][J+1];
sumY += ((r+g+b)/3) * GY[I+1][J+1];
}
}
SUM = abs(sumX) + abs(sumY);
if (SUM > 255)
SUM = 255;
}
*(pPixelDest) = BYTE(SUM);
*(pPixelDest+1) = BYTE(SUM);
*(pPixelDest+2) = BYTE(SUM);
*(pPixelDest+3) = 255;
pPixelSrc += dPixelSrc;
pPixelDest += dPixelDest;
}
pLineSrc += dLineSrc;
pLineDest += dLineDest;
}
sobelDestination->UnlockBits(&dataDest);
}
source->UnlockBits(&dataSrc);
}
}