The figure below is an image grab using TRIPOD - (Template for Real-Time Image PrOcessing Development). TRIPOD gives a programmer the capabilities to process images in real time. The top viewport displays color images taken with a Logitech USB camera. While the bottom viewport first grayscales the image, and then processes it using the Laplace edge detection algorithm.
TRIPOD was written to enable programmers to rapidly compute real-time image processing algorithms. The template consists of a variety of Microsoft Visual C++ source and header files which are integrated to give you the output seen above. The only thing you have to learn is how to incorporate all these source and header files in to one Microsoft Visual project and what source file to insert your image processing code into.
Things you will need to complete this tutorial:
(1) Windows 98 operating system
(2) Microsoft Visual C++ 6.0 (version 5.0 won’t work)
(3) Install
DirectX 8.1
(4) Install QCSDK before plugging in camera
(5) Logitech USB Camera: (Tutorial uses LEGO's Vision Command which is just a Logitech USB
camera in a LEGO casing)
(6) Download tripod.zip (2.5 MB)
Assuming that you have all the necessary steps above complete, now would be a good time to set up your TRIPOD template. To view step-by-step instructions on how to set up a template and to find out where to insert your image processing source code, click on the link below (first see Notes 1 & 2):
Note1: Instead of calling the project “brinarize”, call it “edgelap”.
Note2: Only READ steps 6 & 7 to find out where to insert your code, but do not complete.
Assuming you have followed the step-by-step instructions from the link above, you now have a template set up and are ready to insert your Laplace edge detector source code in the appropriate section. Just to refresh, your added code goes in the "tripodDlg.cpp" file, under the CTripodDlg::doMyImageProcessing function:
To detect edges using the Laplace method, insert code in red into tripodDlg.cpp:
// The destination BMP will be a grayscale version of the source BMP
*(m_destinationBmp + i) = grayValue;
*(m_destinationBmp + i + 1) = grayValue;
*(m_destinationBmp + i + 2) = grayValue;
// Make a copy of m_destinationBmp
*(m_CopyOfDestinationBmp + i) = *(m_destinationBmp + i);
*(m_CopyOfDestinationBmp + i + 1) = *(m_destinationBmp + i + 1);
*(m_CopyOfDestinationBmp + i + 2) = *(m_destinationBmp + i + 2);
}
}
}
void CTripodDlg::doMyImageProcessing(LPBITMAPINFOHEADER lpThisBitmapInfoHeader)
{
// doMyImageProcessing: This is where you'd write your own image processing code
// Task: Read a pixel's grayscale value and process accordingly
unsigned int W, H; // Width and Height of current frame [pixels]
unsigned int row, col; // Pixel's row and col positions
unsigned long i; // Dummy variable for row-column vector
int I, J; // Mask pointers
int MASK[5][5];
int SUM;
float numRowsInMask;
float numColsInMask;
int rowOffset;
int colOffset;
char str[80]; // To print message
CDC *pDC; // Device context need to print message
W = lpThisBitmapInfoHeader->biWidth; // biWidth: number of columns
H = lpThisBitmapInfoHeader->biHeight; // biHeight: number of rows
/* 5x5 Laplace mask. Ref: Myler Handbook p. 135 */
MASK[0][0] = -1; MASK[0][1] = -1; MASK[0][2] = -1; MASK[0][3] = -1; MASK[0][4] = -1;
MASK[1][0] = -1; MASK[1][1] = -1; MASK[1][2] = -1; MASK[1][3] = -1; MASK[1][4] = -1;
MASK[2][0] = -1; MASK[2][1] = -1; MASK[2][2] = 24; MASK[2][3] = -1; MASK[2][4] = -1;
MASK[3][0] = -1; MASK[3][1] = -1; MASK[3][2] = -1; MASK[3][3] = -1; MASK[3][4] = -1;
MASK[4][0] = -1; MASK[4][1] = -1; MASK[4][2] = -1; MASK[4][3] = -1; MASK[4][4] = -1;
// In this example, the grayscale image (stored in m_destinationBmp) is
// manipulated by a 5x5 convolution mask. This mask is used to approximate
// the first derivative which highlights the locations of edges in an image.
// The output is the edge detected bmp using the Laplace method
numRowsInMask = 5; // Laplace mask has 5 rows
numColsInMask = 5; // and 5 columns
rowOffset = (int)((numRowsInMask/2.0)); // offset should be 2
colOffset = (int)((numColsInMask/2.0)); // offset should be 2
for (row = rowOffset; row < (H-1-rowOffset); row++) {
for (col = colOffset; col < (W-1-colOffset); col++) {
// Recall each pixel is composed of 3 bytes
i = (unsigned long)(3*col + 3*row*W);
SUM = 0;
// Add your code to operate on each pixel. For example
// *(m_destinationBmp + i) refers to the ith pixel in the destinationBmp
// Since destinationBmp is a 24-bit grayscale image, you must also apply
// the same operation to *((m_destinationBmp + i + 1) and
// *((m_destinationBmp + i + 2)
/*********************************************
* Laplace Edge detection algorithm
*********************************************/
for(I=-2; I<=2; I++) {
for(J=-2; J<=2; J++) {
SUM = SUM + (int)( (*(m_CopyOfDestinationBmp + 3*col + 3*I + 3*(row+J)*W)) * MASK[I+2][J+2]);
}
}
if(SUM > 255) SUM = 255;
if(SUM < 0) SUM = 0;
*(m_destinationBmp + i) =
*(m_destinationBmp + i + 1) =
*(m_destinationBmp + i + 2) = (BYTE)(SUM);
}
}
// To print message at (row, column) = (75, 580). Comment if not needed
pDC = GetDC();
sprintf(str, "Edge detected using Laplace method");
pDC->TextOut(75, 580, str);
ReleaseDC(pDC);
}
Before compiling, you must also define *m_CopyOfDestinationBmp by inserting the code in red into tripodDlg.h:
protected:
HICON m_hIcon;
CRect m_rectForProcessedView; // Videoportal frame characteristics (width, screen location etc)
LPBITMAPINFOHEADER m_destinationBitmapInfoHeader;
BYTE *m_destinationBmp;
BYTE *m_CopyOfDestinationBmp;
Once you have inserted your Laplace edge detection algorithm, click File -> Save All, Build -> Rebuild All, and Build -> execute edgelap.exe. Your application should launch the TRIPOD viewport and successfully display edge detected images in real-time. To view an explanation of how the Canny algorithm works and steps taken to implement the algorithm into source code, visit my Edge Detection Tutorial.
You are visitor number: