在本周的计算机视觉与模式识别作业中,给定输入图像是两张普通A4打印纸,上面可能有手写笔记或者打印内容但是拍照时角度不正。要求输出:
1. 图像的边缘;
2. 计算 A4纸边缘的各直线方程;
3. 提取A4纸的4个角点。
作业要求的是使用C++的CImg库,与OpenCV和MATLAB相比,CImg还是有点不太方便。
差点忘了贴代码:
// CV_HW2.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include
#include
#include "CImg.h"
using namespace cimg_library;
using namespace std;
/*
CImg<> edgeDetect(CImg<> src) {
int mask[3][3] = { {0,-1,0},{-1,4,-1},{0,-1,0} };
int width = src.width();
int height = src.height();
CImg newImg(width, height, 1, 3);
newImg.fill(0);
for (int i = 1; i < width - 1; i++) {
for (int j = 1; j < height - 1; j++) {
for (int k = 0; k < 3; k++) {
double sum = 0.0;
for (int row = 0; row < 3; row++) {
for (int col = 0; col < 3; col++) {
sum += mask[row][col] * src(i - 1 + row, j - 1 + col, k);
}
}
if (sum < 0)
sum = 0;
else if (sum > 255)
sum = 255;
newImg(i, j, k) = sum;
}
}
}
newImg.display();
return newImg;
}
*/
CImg<> edgeDetect(CImg<> src) {
int sobelX[3][3] = { { -1,0,1 },{ -2,0,2 },{ -1,0,1 } };
int sobelY[3][3] = { { 1,2,1 },{ 0,0,0 },{ -1,-2,-1 } };
int width = src.width();
int height = src.height();
CImg<double> G(width, height, 1, 3);
CImg<double> newImg(width, height, 1, 3);
newImg.fill(0);
for (int i = 1; i < width - 1; i++) {
for (int j = 1; j < height - 1; j++) {
double sumX = 0.0;
double sumY = 0.0;
for (int row = 0; row < 3; row++) {
for (int col = 0; col < 3; col++) {
sumX += sobelX[row][col] * src(i - 1 + row, j - 1 + col, 0);
sumY += sobelY[row][col] * src(i - 1 + row, j - 1 + col, 0);
}
}
newImg(i, j, 0) = sqrt(sumX*sumX + sumY*sumY) > 85 ? 255 : 0;
newImg(i, j, 1) = newImg(i, j, 0);
newImg(i, j, 2) = newImg(i, j, 0);
}
}
newImg.display();
//newImg.dilate(3.5);
return newImg;
}
void print(double k, double b) {
cout << "y = " << k << " * " << "x";
if (b > 0) {
cout << "+" << b;
}
else if (b < 0) {
cout << b;
}
cout << endl;
}
void line(double x1, double y1, double x2, double y2) {
double k = (y1 - y2) / (x1 - x2);
double b =y1 - k*x1;
print(k, b);
}
CImg<> pointDetect(CImg<> src) {
int width = src.width();
int height = src.height();
double upLeftX = 0.0;
double upLeftY = 0.0;
double downLeftX = 0.0;
double downLeftY = 0.0;
double upRightX = 0.0;
double upRightY = 0.0;
double downRightX = 0.0;
double downRightY = 0.0;
//求左上顶点
for (int j = 100; j < height - 50; j++) {
for (int i = 100; i < width; i++) {
if (upLeftX == 0 && upLeftY == 0 && src(i, j, 0) == 1) {
upLeftX = i;
upLeftY = j;
break;
}
}
if (upLeftX || upLeftY) {
break;
}
}
//求右上顶点
for (int i = width - 50; i >= 0; i--) {
for (int j = 100; j < height; j++) {
if (upRightX == 0 && upRightY == 0 && src(i, j,0) == 1) {
upRightX = i;
upRightY = j;
break;
}
}
if (upRightX || upRightY) {
break;
}
}
//求左下顶点
for (int j = height - 110; j >= 0; j--) {
for (int i = width-100; i >= 0; i--) {
if (downLeftX == 0 && downLeftY == 0 && src(i, j, 0) == 1) {
downLeftX = i;
downLeftY = j;
break;
}
}
if (downLeftX || downLeftY) {
break;
}
}
//求右下顶点
for (int j = downLeftY-1; j >= 0; j--) {
for (int i = width - 50; i >= 0; i--) {
if (downRightX == 0 && downRightY == 0 && src(i, j, 0) == 1
&& abs((i - downLeftX) - (upRightX - upLeftX)) < 60) {
downRightX = i;
downRightY = j;
break;
}
}
if (downRightX && downRightY) {
break;
}
}
cout << "图像的四个角点坐标分别是:" << endl;
cout << "左上角upLeft:(" << upLeftX << "," << upLeftY << ")"<< endl;
cout << "右上角upRight:(" << upRightX << " ," << upRightY << ")" << endl;
cout << "右下角downRight:(" << downRightX << " ," << downRightY << ")" << endl;
cout << "左下角downLeft:(" << downLeftX << " ," << downLeftY << ")" << endl;
cout << "上方直线方程为:";
line(upLeftX, upLeftY, upRightX, upRightY);
cout << "左方直线方程为:";
line(upLeftX, upLeftY, downLeftX, downLeftY);
cout << "右方直线方程为:";
line(upRightX, upRightY, downRightX, downRightY);
cout << "下方直线方程为:";
line(downLeftX, downLeftY, downRightX, downRightY);
//src.dilate(3);
//src.display();
return src;
}
CImg<> harrisCorners(CImg<> src) {
int width = src.width();
int height = src.height();
int horizontal[3][3] = { { 5,0, -5 },{ 8,0,-8 }, { 5,0,-5 } };
int vertical[3][3] = { { 5,8, 5 },{ 0,0,0 },{ -5,-8,-5 } };
CImg<double> Ix(width, height, 1, 3);
CImg<double> Iy(width, height, 1, 3);
CImg<double> Ixx(width, height, 1, 3);
CImg<double> Iyy(width, height, 1, 3);
CImg<double> Ixy(width, height, 1, 3);
//x、y方向梯度
for (int i = 1; i < width; i++) {
for (int j = 1; j < height - 1; j++) {
for (int k = 0; k < 3; k++) {
double sumX = 0.0;
double sumY = 0.0;
for (int row = 0; row < 3; row++) {
for (int col = 0; col < 3; col++) {
sumX += src(row + i - 1, col + j - 1, k)*horizontal[row][col];
sumY += src(row + i - 1, col + j - 1, k)*vertical[row][col];
}
}
Ix(i, j, k) = sumX;
Iy(i, j, k) = sumY;
}
}
}
//两个方向梯度的乘积
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
for (int k = 0; k < 3; k++) {
Ixx(i, j, k) = Ix(i, j, k)*Ix(i, j, k);
Iyy(i, j, k) = Iy(i, j, k)*Iy(i, j, k);
Ixy(i, j, k) = Ix(i, j, k)*Iy(i, j, k);
}
}
}
//高斯加权
CImg<double> R(width, height, 1, 3);
double pi = 3.1415926;
double alpha = 0.04;
double maxR[3] = { INT_MIN };
double threshHold[3];
int gauss[3][3] = { {1,2,1},{2,4,2},{1,2,1} };
for (int i = 1; i < width-1; i++) {
for (int j = 1; j < height-1; j++) {
for (int k = 0; k < 3; k++) {
double A = 0.0;
double B = 0.0;
double C = 0.0;
for (int row = 0; row < 3; row++) {
for (int col = 0; col < 3; col++) {
A += Ixx(row + i - 1, col + j - 1, k)*gauss[row][col];
B += Ixy(row + i - 1, col + j - 1, k)*gauss[row][col];
C += Iyy(row + i - 1, col + j - 1, k)*gauss[row][col];
}
}
A /= 16.0;
B /= 16.0;
C /= 16.0;
//double A = (Ixx(i - 1, j - 1, k) + Ixx(i - 1, j + 1, k) + Ixx(i + 1, j - 1, k) + Ixx(i + 1, j + 1, k) + (Ixx(i - 1, j, k) + Ixx(i, j - 1, k) + Ixx(i + 1, j, k) + Ixx(i, j + 1, k)) * 2.0 + Ixx(i, j, k) * 4) / 16;
//double A = exp(-Ixx(i, j, k)*Ixx(i, j, k) / 8.0) / (2.0 * sqrt(2.0 * pi));
//double B = exp(-Ixy(i, j, k)*Ixy(i, j, k) / 8.0) / (2.0 * sqrt(2.0 * pi));
//double C = exp(-Iyy(i, j, k)*Iyy(i, j, k) / 8.0) / (2.0 * sqrt(2.0 * pi));
//Harris响应值R
R(i, j, k) = (A*C - B*B) - alpha*(A + C)*(A + C);
if (maxR[k] < R(i, j, k)) {
maxR[k] = R(i, j, k);
threshHold[k] = 0.01*maxR[k];
}
}
}
}
//小于阈值的R置为0
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
for (int k = 0; k < 3; k++) {
if (R(i, j, k) < threshHold[k]) {
R(i, j, k) = 0;
}
}
}
}
CImg<double> result(width, height, 1, 3);
result.fill(0);
for (int i = 1; i < width - 1; i++) {
for (int j = 1; j < height - 1; j++) {
for (int k = 0; k < 3; k++) {
//局部非最大值抑制
if (R(i, j, k) > threshHold[k] && R(i, j, k) > R(i - 1, j - 1, k) && R(i, j, k) > R(i - 1, j, k) && R(i, j, k) > R(i - 1, j + 1, k)
&& R(i, j, k) > R(i, j - 1, k) && R(i, j, k) > R(i, j + 1, k) && R(i, j, k) > R(i + 1, j - 1, k) && R(i, j, k) > R(i + 1, j, k)
&& R(i, j, k) > R(i + 1, j + 1, k)) {
result(i, j, k) = 1;
}
}
}
}
pointDetect(result);
unsigned char color[] = { 255,255,0 };
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
if (result(i, j, 0) == 1) {
src.draw_circle(i, j, 5, color);
}
}
}
src.display();
return src;
}
int main()
{
CImg<> src1("1.bmp");
CImg<> tmp = edgeDetect(src1);
tmp.save_bmp("edge1.bmp");
CImg<> tmp2 = harrisCorners(src1);
tmp2.save_bmp("harris1.bmp");
CImg<> src("2.bmp");
CImg<> tmp3 = edgeDetect(src);
tmp3.save_bmp("edge2.bmp");
CImg<> tmp5 = harrisCorners(src);
tmp5.save_bmp("harris2.bmp");
return 0;
}