/*******************************************************************************
Detect Harris corners.

    image: input image
    sigma: standard deviation of Gaussian used to blur corner detector
    thres: Threshold for detecting corners
    interestPts: returned interest points
    numInterestPts: number of interest points returned
    imageDisplay: image returned to display (for debugging)
*******************************************************************************/
void MainWindow::HarrisCornerDetector(QImage image, double sigma, double thres, CIntPt **interestPts, int &numInterestPts, QImage &imageDisplay)
{
    int r, c;
	double harrisScaleFactor = 19.0;

    int imageWidth = image.width();
    int imageHeight = image.height();
	if((!imageWidth)||(!imageHeight))
	{
		return;
	}

    double *buffer = new double [imageWidth * imageHeight];
    QRgb pixel;

    numInterestPts = 0;

    // We'll compute the corner response using just the green channel
    for(r = 0; r < imageHeight; r++)
	{
       for(c = 0; c < imageWidth; c++)
       {
            pixel = image.pixel(c, r);
			buffer[r * imageWidth + c] = (double) qGreen(pixel);
       }
	}

	
	// Define a small window for examining the image. This window will be used
	// to compute the covariance matrix and Harris response at each point.
	// Since we'll be computing a Gaussian sum of the values in the window,
	// let's size it so the radius is sigma * 3 (99.7% of values are accounted for).

	// Let's expand the buffer so that we can calculate the derivatives
	// for the original buffer data, centered in the expanded buffer.
	int expandedBufferWidth = imageWidth + 2;
	int expandedBufferHeight = imageHeight + 2;
	double *expandedBuffer = new double [expandedBufferWidth * expandedBufferHeight];
	zeroBorders(expandedBuffer, 1, expandedBufferWidth, expandedBufferHeight);

	// Now, fill in our expanded buffer with the contents of the first buffer (centered).
    for(r = 1; r < imageHeight + 1; r++)
	{
       for(c = 1; c < imageWidth + 1; c++)
       {
			expandedBuffer[r * (expandedBufferWidth) + c] = buffer[(r - 1) * imageWidth + (c - 1)];
	   }
	}
	
    // 1st-derivative kernel to convolve with the image
    double *firstDKernel = new double [3];
	firstDKernel[0] = -1.0;
	firstDKernel[1] = 0.0;
	firstDKernel[2] = 1.0;

	// Set up image copies for the x and y derivatives, as well as the arrays
	// for which we'll use them
	double * x_deriv = new double [expandedBufferWidth * expandedBufferHeight];
	double * y_deriv = new double [expandedBufferWidth * expandedBufferHeight];
	double * y_deriv_squared = new double [imageWidth * imageHeight];
	double * x_deriv_squared = new double [imageWidth * imageHeight];
	double * xy_deriv = new double [imageWidth * imageHeight];

	// Copy expanded buffer into the x- and y-derivative buffers
	for(r = 0; r < expandedBufferHeight; r++)
	{
		for(c = 0; c < expandedBufferWidth; c++)
        {
            x_deriv[r * expandedBufferWidth + c] = expandedBuffer[r * expandedBufferWidth + c];
			y_deriv[r * expandedBufferWidth + c] = expandedBuffer[r * expandedBufferWidth + c];
        }
	}

	// Calculate the x-derivative of the buffer image
	convolve(x_deriv, expandedBufferWidth, expandedBufferHeight, firstDKernel, 3, 1, 1, 1, false, false);

	// Calculate the y-derivative of the buffer image
	convolve(y_deriv, expandedBufferWidth, expandedBufferHeight, firstDKernel, 1, 3, 1, 1, false, false);

	// Calculate the x-derivative squared of the buffer image
	for(r = 0; r < imageHeight; r++)
	{
		for(c = 0; c < imageWidth; c++)
        {
			x_deriv_squared[r * imageWidth + c] = x_deriv[(r + 1) * expandedBufferWidth + (c + 1)] * x_deriv[(r + 1) * expandedBufferWidth + (c + 1)];
        }
	}


	// Now blur it
	SeparableGaussianBlurImage(x_deriv_squared, imageWidth, imageHeight, sigma);

	// Calculate the y-derivative squared of the buffer image
	for(r = 0; r < imageHeight; r++)
	{
		for(c = 0; c < imageWidth; c++)
        {
			y_deriv_squared[r * imageWidth + c] = y_deriv[(r + 1) * expandedBufferWidth + (c + 1)] * y_deriv[(r + 1) * expandedBufferWidth + (c + 1)];
        }
	}


	// Now blur it
	SeparableGaussianBlurImage(y_deriv_squared, imageWidth, imageHeight, sigma);

	// Calculate the x-derivative * y-derivative of the buffer image
	for(r = 0; r < imageHeight; r++)
	{
		for(c = 0; c < imageWidth; c++)
        {
			xy_deriv[r * imageWidth + c] = x_deriv[(r + 1) * expandedBufferWidth + (c + 1)] * y_deriv[(r + 1) * expandedBufferWidth + (c + 1)];
        }
	}
	// Now blur it
	SeparableGaussianBlurImage(xy_deriv, imageWidth, imageHeight, sigma);

	// Set up a Harris response buffer to hold the Harris response for each pixel
	double *harrisResponseBuffer = new double [imageWidth * imageHeight];
	double dx_squared, dy_squared, dxdy, determinant, trace;

	// For each pixel in the image
	for(r = 0; r < imageHeight; r++)
	{
		for(c = 0; c < imageWidth; c++)
		{
			// Get our dx^2 value
			dx_squared = x_deriv_squared[r * imageWidth + c];

			// Get our dy^2 value
			dy_squared = y_deriv_squared[r * imageWidth + c];

			// Get our dxdy value
			dxdy = xy_deriv[r * imageWidth + c];

			// Assuming a matrix like this:
			//
			//		dx^2	dxdy
			//	[					]
			//		dxdy	dy^2
			//
			
			// Find the determinant of the matrix
			determinant = dx_squared * dy_squared - dxdy * dxdy;

			// Find the trace of the matrix
			trace = dx_squared + dy_squared;

			// Finally, plug the determinant/trace for this point into the Harris response buffer
			if(trace == 0)
			{
				harrisResponseBuffer[r * imageWidth + c] = 0.0;
			}
			else
			{
				harrisResponseBuffer[r * imageWidth + c] = abs(determinant / trace) / harrisScaleFactor;
			}
		}
	}

	double min = 0.0;
	double max = 0.0;

	// Now that we've populated the Harris response buffer, let's cull out responses below the threshold
	for(r = 0; r < imageHeight; r++)
	{
		for(c = 0; c < imageWidth; c++)
		{

			if((harrisResponseBuffer[r * imageWidth + c] != 0)&&(harrisResponseBuffer[r * imageWidth + c] < min))
			{
				min = harrisResponseBuffer[r * imageWidth + c];
			}
			if(harrisResponseBuffer[r * imageWidth + c] > max)
			{
				max = harrisResponseBuffer[r * imageWidth + c];
			}


			if(harrisResponseBuffer[r * imageWidth + c] < thres)
			{
				harrisResponseBuffer[r * imageWidth + c] = 0.0;
			}
		}
	}

	// Cull out any points in the Harris response that aren't local peaks in their 3x3 neighborhood
	localMaxima(harrisResponseBuffer, imageWidth, imageHeight, 5);

	// Count interest points in Harris response
	numInterestPts = 0;
	for(r = 0; r < imageHeight; r++)
	{
		for(c = 0; c < imageWidth; c++)
		{
			
			if(harrisResponseBuffer[r * imageWidth + c] > 0.0)
			{
				numInterestPts++;
			}
		}
	}


	// Allocate an array in which store our interest points
	*interestPts = new CIntPt[numInterestPts];

	// Store our interest points
	int i = 0;
	for(r = 0; r < imageHeight; r++)
	{
		for(c = 0; c < imageWidth; c++)
		{
			if(harrisResponseBuffer[r * imageWidth + c] > 0.0)
			{
				(*interestPts)[i].m_X = c;
				(*interestPts)[i].m_Y = r;
				i++;
			}
		}
	}

    // Once you are done finding the interest points, display them on the image
    DrawInterestPoints(*interestPts, numInterestPts, imageDisplay);

    delete [] buffer;
	delete [] firstDKernel;
	delete [] harrisResponseBuffer;
	delete [] x_deriv;
	delete [] y_deriv;
	delete [] x_deriv_squared;
	delete [] y_deriv_squared;
	delete [] xy_deriv;
	delete [] expandedBuffer;
}
Esempio n. 2
0
/*******************************************************************************
Detect Harris corners.
    image - input image
    sigma - standard deviation of Gaussian used to blur corner detector
    thres - Threshold for detecting corners
    interestPts - returned interest points
    numInterestsPts - number of interest points returned
    imageDisplay - image returned to display (for debugging)
*******************************************************************************/
void MainWindow::HarrisCornerDetector(QImage image, double sigma, double thres, CIntPt **interestPts, int &numInterestsPts, QImage &imageDisplay)
{
    int r, c;
    int w = image.width();
    int h = image.height();
    double *buffer = new double [w*h];
    QRgb pixel;

    numInterestsPts = 0;

    // Set up matrix
    double *ix = new double[w * h];
    double *iy = new double[w * h];
    double *ixy = new double[w * h];
    double *harris = new double[w * h];

    // Compute the corner response using green band only
    // Initialize ixix, iyiy, ixiy
    for(r = 0; r < h; r++) {
        for(c = 0; c < w; c++) {
            pixel = image.pixel(c, r);

            buffer[r * w + c] = (double) qGreen(pixel);

            ix[r * w + c] = 0.0;
            iy[r * w + c] = 0.0;
            ixy[r * w + c] = 0.0;
        }
    }

    

    // Compute the ixix, iyiy, ixiy
    for(r = 1; r < h - 1; r++) {
        for (c = 1; c < w - 1; c++) {
            double left = buffer[r * w + c - 1];
            double right = buffer[r * w + c + 1];
            double bottom = buffer[(r + 1) * w + c];
            double top = buffer[(r - 1) * w + c];

            ix[r * w + c] = pow(right - left, 2);
            iy[r * w + c] = pow(bottom - top, 2);
            ixy[r * w + c] = (right - left) * (bottom - top);
        }
    }

    // Smooth
    SeparableGaussianBlurImage(ix, w, h, sigma);
    SeparableGaussianBlurImage(iy, w, h, sigma);
    SeparableGaussianBlurImage(ixy, w, h, sigma);

    // Compute Harris = det(H) / trace(H)
    for(r = 1; r < h - 1; r++) {
        for(c = 1; c < w - 1; c++) {
            double xx = ix[r * w + c];
            double yy = iy[r * w + c];
            double xy = ixy[r * w + c];

            double det = xx * yy - xy * xy;
            double trace = xx + yy;

            double val = 0.0;
            if(trace > 0.0)
                val = det / trace;

            harris[r * w + c] = val;

            // Scale for displaying
            val = max(50.0, min(255.0, val));

            imageDisplay.setPixel(c, r, qRgb(val, val, val));
        }
    }

    // Compute interest points and display
    for(r = 1; r < h - 1; r++) {
        for(c = 1; c < w - 1; c++) {

            int x, y;
            bool max = true;
            // The corner response > threshold
            // Might be interesting to look at
            if(harris[r * w + c] > thres) {
                for(x = -1; x <= 1; x++) {
                    for(y = -1; y <= 1; y++) {
                        // Not local miximum of surrounding pixels
                        if(harris[r * w + c] < harris[(r + x) * w + c + y]) {
                            max = false;
                        }

                    }
                }
                // Local maximum, corner
                if(max) {
                    numInterestsPts++;
                    imageDisplay.setPixel(c, r, qRgb((int)255, (int)0, (int)0));
                }
            }
        }
    }


    // Store interest points
    // The descriptor of the interest point is stored in m_Desc
    // The length of the descriptor is m_DescSize, if m_DescSize = 0, then it is not valid.
    *interestPts = new CIntPt [numInterestsPts];
    int i = 0;
    for(r = 1; r < h - 1; r++) {
        for(c = 1; c < w - 1; c++) {
            pixel = imageDisplay.pixel(c, r);
            // Interest point value
            if(qRed(pixel) == 255 && qGreen(pixel) == 0 && qBlue(pixel) == 0) {
                (*interestPts)[i].m_X = (double) c;
                (*interestPts)[i].m_Y = (double) r;
                i++;
            }
        }
    }


    // Once you are done finding the interest points, display them on the image
    DrawInterestPoints(*interestPts, numInterestsPts, imageDisplay);

    // Clean up
    delete [] buffer;
    delete [] ix;
    delete [] ixy;
    delete [] iy;
    delete [] harris;
}