harris.h
#ifndef HARRIS_H_
#define HARRIS_H_
#include <iostream>
#include <windows.h>
#include <stdio.h>
#include <string>
#include <conio.h>
#include <easyx.h>
#include <vector>
#include <algorithm>
#include <math.h>
using namespace std;
typedef unsigned char uchar;
typedef vector<vector<long> > LONG_2DVEC;
typedef vector<vector<float> > FLOAT_2DVEC;
typedef vector<vector<uchar> > UCHAR_2DVEC;
typedef vector<vector<int> > INT_2DVEC;
typedef vector<long> LONG_VEC;
typedef vector<float> FLOAT_VEC;
typedef vector<int> INT_VEC;
typedef vector<vector<int> > CORNER_VEC;
void ConvertStringToWchar(string sToMatch, wchar_t * lpwsz);
IMAGE ConvertBGRToGRAY(IMAGE srcImage);
IMAGE SobelGradintX(IMAGE grayImage);
IMAGE SobelGradintY(IMAGE grayImage);
INT_2DVEC SobelGradint2DVectorX(IMAGE grayImage);
INT_2DVEC SobelGradint2DVectorY(IMAGE grayImage);
LONG_2DVEC SobelXX(IMAGE GXImage);
LONG_2DVEC SobelXY(IMAGE GXImage, IMAGE GYImage);
LONG_2DVEC SobelYY(IMAGE GYImage);
FLOAT_2DVEC HarrisResponse(LONG_2DVEC GradXX, LONG_2DVEC GradXY, LONG_2DVEC GradYY, float k);
UCHAR_2DVEC DataNormalize(FLOAT_2DVEC Response);
CORNER_VEC LocalMaxValue(UCHAR_2DVEC Response);
CORNER_VEC HarrisCornerDetection(IMAGE srcImage);
void PaintCorner(CORNER_VEC CORNER_VECTOR, IMAGE srcIMAGE);
#endif // !HARRIS_H_
harris.c
#include "harris.h"
void ConvertStringToWchar(string sToMatch, wchar_t * lpwsz)
{
// 计算转换后宽字符串的长度。(不包含字符串结束符)
int iWLen = MultiByteToWideChar(CP_ACP, 0, sToMatch.c_str(), sToMatch.size(), 0, 0);
MultiByteToWideChar(CP_ACP, 0, sToMatch.c_str(), sToMatch.size(), lpwsz, iWLen); // 正式转换。
lpwsz[iWLen] = L'\0';
}
IMAGE ConvertBGRToGRAY(IMAGE srcImage) {
int rows = srcImage.getheight();
int cols = srcImage.getwidth();
IMAGE grayImage = srcImage;
DWORD* GRAY_PTR = GetImageBuffer(&grayImage);
vector<uchar> vec(cols, 0);
vector<vector<uchar> > Vec(rows, vec);
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
*GRAY_PTR = BGR(*GRAY_PTR);//显存是RGB,图像在内存存储为
Vec.at(i).at(j) = (GetRValue(*GRAY_PTR) * 299 + GetGValue(*GRAY_PTR) * 587 + GetBValue(*GRAY_PTR) * 114 +500) / 1000;
*GRAY_PTR = RGB(Vec.at(i).at(j), Vec.at(i).at(j), Vec.at(i).at(j));
GRAY_PTR++;
}
}
GRAY_PTR -= rows * cols;
return grayImage;
}
IMAGE SobelGradintX(IMAGE srcImage) {
int rows = srcImage.getheight();
int cols = srcImage.getwidth();
DWORD* PTR = GetImageBuffer(&srcImage);
IMAGE GXImage = srcImage;
DWORD* GX_PTR = GetImageBuffer(&GXImage);
int Grad = 0;
for (int i = 1; i < rows - 1; i++)
{
for (int j = 1; j < cols - 1; j++)
{
Grad = (GetRValue(*(PTR+(i-1)* cols+j-1)) + 2* GetRValue(*(PTR + (i-1)*cols + j))
+ GetRValue(*(PTR+(i-1) * cols + j+1)))- (GetRValue(*(PTR+(i+1)* cols+j-1)) +
2 * GetRValue(*(PTR+(i+1)* cols+j)) + GetRValue(*(PTR+(i+1)* cols+j +1)));
*(GX_PTR + i * cols +j) = RGB(abs(Grad), abs(Grad), abs(Grad));
}
}
return GXImage;
}
INT_2DVEC SobelGradint2DVectorX(IMAGE grayImage) {
int rows = grayImage.getheight();
int cols = grayImage.getwidth();
INT_VEC vec(cols,0);
INT_2DVEC Vec(rows,vec);
DWORD* PTR = GetImageBuffer(&grayImage);
int Grad = 0;
for (int i = 1; i < rows - 1; i++)
{
for (int j = 1; j < cols - 1; j++)
{
Grad = (GetRValue(*(PTR + (i - 1)* cols + j - 1)) + 2 * GetRValue(*(PTR + (i - 1)*cols + j))
+ GetRValue(*(PTR + (i - 1) * cols + j + 1))) - (GetRValue(*(PTR + (i + 1)* cols + j - 1)) +
2 * GetRValue(*(PTR + (i + 1)* cols + j)) + GetRValue(*(PTR + (i + 1)* cols + j + 1)));
Vec.at(i).at(j) = abs(Grad);
}
}
return Vec;
}
IMAGE SobelGradintY(IMAGE srcImage) {
int rows = srcImage.getheight();
int cols = srcImage.getwidth();
DWORD* PTR = GetImageBuffer(&srcImage);
IMAGE GYImage = srcImage;
DWORD* GY_PTR = GetImageBuffer(&GYImage);
int Grad = 0;
for (int i = 1; i < rows - 1; i++)
{
for (int j = 1; j < cols - 1; j++)
{
Grad = (GetRValue(*(PTR + (i - 1)* cols + j + 1)) + 2 * GetRValue(*(PTR + i * cols + j + 1))
+ GetRValue (*(PTR + (i + 1)* cols + j + 1)))- (GetRValue(*(PTR + (i - 1)* cols + j - 1))
+ 2 * GetRValue(*(PTR + i * cols + j - 1)) + GetRValue(*(PTR + (i + 1)* cols + j - 1)));
*(GY_PTR + i * cols + j) = RGB(abs(Grad), abs(Grad), abs(Grad));
}
}
return GYImage;
}
INT_2DVEC SobelGradint2DVectorY(IMAGE srcImage) {
int rows = srcImage.getheight();
int cols = srcImage.getwidth();
INT_VEC vec(cols, 0);
INT_2DVEC Vec(rows, vec);
DWORD* PTR = GetImageBuffer(&srcImage);
int Grad = 0;
for (int i = 1; i < rows - 1; i++)
{
for (int j = 1; j < cols - 1; j++)
{
Grad = (GetRValue(*(PTR + (i - 1)* cols + j + 1)) + 2 * GetRValue(*(PTR + i * cols + j + 1))
+ GetRValue(*(PTR + (i + 1)* cols + j + 1))) - (GetRValue(*(PTR + (i - 1)* cols + j - 1))
+ 2 * GetRValue(*(PTR + i * cols + j - 1)) + GetRValue(*(PTR + (i + 1)* cols + j - 1)));
Vec.at(i).at(j) = abs(Grad);
}
}
return Vec;
}
LONG_2DVEC SobelXX(IMAGE GXImage) {
int rows = GXImage.getheight();
int cols = GXImage.getwidth();
DWORD* GX_PTR = GetImageBuffer(&GXImage);
LONG_2DVEC Vec ;
LONG_VEC vec;
int GradX = 0;
for (int i = 0; i < rows ; i++)
{
for (int j = 0; j < cols; j++)
{
GradX = GetRValue(*(GX_PTR + i * cols + j));
vec.push_back(GradX * GradX);
}
Vec.push_back(vec);
vec.clear();
}
return Vec;
}
LONG_2DVEC SobelXY(IMAGE GXImage, IMAGE GYImage) {
int rows = GXImage.getheight();
int cols = GXImage.getwidth();
DWORD* GX_PTR = GetImageBuffer(&GXImage);
DWORD* GY_PTR = GetImageBuffer(&GYImage);
LONG_2DVEC Vec;
LONG_VEC vec;
int GradX = 0;
int GradY = 0;
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
GradX = GetRValue(*(GX_PTR + i * cols + j));
GradY = GetRValue(*(GY_PTR + i * cols + j));
vec.push_back(GradX * GradY);
}
Vec.push_back(vec);
vec.clear();
}
return Vec;
}
LONG_2DVEC SobelYY(IMAGE GYImage) {
int rows = GYImage.getheight();
int cols = GYImage.getwidth();
DWORD* PTR = GetImageBuffer(&GYImage);
LONG_2DVEC Vec;
LONG_VEC vec;
int Grad = 0;
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
Grad = GetRValue(*(PTR + i * cols + j));
vec.push_back(Grad * Grad);
}
Vec.push_back(vec);
vec.clear();
}
return Vec;
}
FLOAT_2DVEC HarrisResponse(LONG_2DVEC GradXX, LONG_2DVEC GradXY, LONG_2DVEC GradYY,float k) {
int rows = GradXX.size();
int cols = GradXX.at(0).size();
FLOAT_2DVEC Vec;
FLOAT_VEC vec;
float result = 0;
for (int i = 0; i < rows; i++)
{
vec.clear();
for (int j = 0; j <cols; j++)
{
long a = GradXX.at(i).at(j);
long b = GradYY.at(i).at(j);
long c = GradXY.at(i).at(j);
result= abs(a * b - c * c - k * (a + b)*(a + b));
vec.push_back(result);
}
Vec.push_back(vec);
}
return Vec;
}
UCHAR_2DVEC DataNormalize(FLOAT_2DVEC Response) {
FLOAT_2DVEC::iterator It1;
int max = 0;
int min = 0;
for (It1 = Response.begin(); It1 != Response.end(); It1++) {
if (max < *max_element((*It1).begin(), (*It1).end() )) {
max = *max_element((*It1).begin(), (*It1).end());
}
else {
max = max;
}
if (min > *max_element((*It1).begin(), (*It1).end() )) {
min = *max_element((*It1).begin(), (*It1).end());
}
else {
min = min;
}
}
UCHAR_2DVEC ResponseNorm;
vector<uchar> vec;
FLOAT_VEC::iterator It2;
for (It1 = Response.begin(); It1 != Response.end(); It1++) {
vec.clear();
for (It2 = (*It1).begin(); It2 != (*It1).end(); It2++) {
vec.push_back(ceil(((*It2) / (max - min))* 255));
}
ResponseNorm.push_back(vec);
}
return ResponseNorm;
}
CORNER_VEC LocalMaxValue(UCHAR_2DVEC ResponseNorm) {
int rows = ResponseNorm.size();
int cols = ResponseNorm.at(0).size();
CORNER_VEC corner_vec;
vector<int> vec;
for (int i = 1; i < rows - 1; i++)
{
for (int j = 1; j <cols - 1; j++)
{
if ( ResponseNorm.at(i).at(j) > ResponseNorm.at(i - 1).at(j - 1) &&
ResponseNorm.at(i).at(j) > ResponseNorm.at(i - 1).at(j) &&
ResponseNorm.at(i).at(j) > ResponseNorm.at(i - 1).at(j + 1) &&
ResponseNorm.at(i).at(j) > ResponseNorm.at(i).at(j - 1) &&
ResponseNorm.at(i).at(j) > ResponseNorm.at(i).at(j + 1) &&
ResponseNorm.at(i).at(j) > ResponseNorm.at(i + 1).at(j - 1) &&
ResponseNorm.at(i).at(j) > ResponseNorm.at(i + 1).at(j) &&
ResponseNorm.at(i).at(j) > ResponseNorm.at(i+1).at(j + 1)){
if (ResponseNorm.at(i).at(j) > 200){
vec.push_back(i);
vec.push_back(j);
corner_vec.push_back(vec);
vec.clear();
}
}
}
}
return corner_vec;
}
CORNER_VEC HarrisCornerDetection(IMAGE srcImage) {
cout << endl;
cout << "start detecting corners,please wait patiently..." << endl;
int rows = srcImage.getheight();
int cols = srcImage.getwidth();
//DWORD* PTR = GetImageBuffer(&srcImage);
//定义角点位置向量
IMAGE grayImage = ConvertBGRToGRAY(srcImage);
IMAGE GX = SobelGradintX(grayImage);
IMAGE GY = SobelGradintY(grayImage);
LONG_2DVEC GradXX = SobelXX(GX);
LONG_2DVEC GradXY = SobelXY(GX,GY);
LONG_2DVEC GradYY = SobelXX(GY);
FLOAT_2DVEC Response = HarrisResponse(GradXX, GradXY, GradYY,0.05);
UCHAR_2DVEC ResponseNorm = DataNormalize( Response);
CORNER_VEC CORNER_VECTOR = LocalMaxValue(ResponseNorm);
cout << "detection end." << endl;
cout << "The number of corners detected is: " << CORNER_VECTOR.size() << endl;
return CORNER_VECTOR;
}
void PaintCorner(CORNER_VEC CORNER_VECTOR,IMAGE srcImage) {
initgraph(srcImage.getwidth(), srcImage.getheight(), EW_SHOWCONSOLE | EW_NOCLOSE | EW_NOMINIMIZE);
putimage(0, 0, &srcImage);
setlinecolor(GREEN);
for (int i = 0; i < CORNER_VECTOR.size(); i++) {
circle(CORNER_VECTOR.at(i).at(0), CORNER_VECTOR.at(i).at(1), 10);
}
FlushBatchDraw();
}
main.c
#include "harris.h"
int main()
{
cout << "***************** CORNERS DETECTION *****************" << endl;
cout << endl;
cout << endl;
while (1) {
cout << "Whether to use the default image(Y/N): ";
char ch ;
cin >> ch;
string filename;
if (ch == 'Y') {
filename = "building.jpg";
}
else {
cout << "Please enter a image name: ";
cin >> filename;
}
cout << "The image name is: " << filename << endl;
int length = filename.size();
wchar_t *lpwsz = new wchar_t[length + 1];
ConvertStringToWchar(filename, lpwsz);
IMAGE srcImage;
loadimage(&srcImage, lpwsz);
delete[]lpwsz;
DWORD* SRC_PTR = GetImageBuffer(&srcImage);
//CORNER_VEC CORNER_VECTOR;
if (SRC_PTR == NULL) {
cout << "There are no the image named " << filename << endl;
cout << "Click any key to continue." << endl;
cout << endl;
}
else{
int imageHight, imageWidth;
imageHight = srcImage.getheight();
imageWidth = srcImage.getwidth();
IMAGE grayImage = ConvertBGRToGRAY(srcImage);
initgraph(imageWidth, imageHight, EW_SHOWCONSOLE |EW_NOCLOSE | EW_NOMINIMIZE);
putimage(0, 0, &srcImage);
cout << "Click any key to start detecting corners." << endl;
_getch();
CORNER_VEC CORNER_VECTOR = HarrisCornerDetection(srcImage);
cout << endl;
cout << "Click any key to paint corners detected." << endl;
_getch();
closegraph();
IMAGE img = srcImage;
PaintCorner(CORNER_VECTOR, img);
cout << endl;
cout << "Click any key to close window." << endl;
_getch();
closegraph();
}
cout << endl;
cout << "End detecting or not(Y/N): ";
char end;
cin >> end;
if (end == 'Y') {
exit(0);
}
cout << endl;
}
return 0;
}