使用方法:创建win32空项目(不是控制台),右击项目选属性--常规--MFC--的使用--共享DLL中,然后导入下面十个文件
一、transform.h
#pragma once
#ifndef TRANSFORM_H
#define TRANSFORM_H
#endif // TRANSFORM_H
void DoubleToString(double xx, int n, char* ans);
二、transform.cpp
#include<stdio.h>
#include<math.h>
void DoubleToString(double xx, int n, char* ans) {
int base = pow(10, n);
double yy = xx*base;
int y = (int)yy;
y %= base;
int x = (int)xx;
//cout<<x<<' '<<y<<endl;
int idx = 0;
if (y == 0)ans[idx++] = '0';
while (y>0) {
ans[idx++] = '0' + y % 10;
y /= 10;
}
ans[idx++] = '.';
if (x == 0)ans[idx++] = '0';
while (x>0) {
ans[idx++] = '0' + x % 10;
x /= 10;
}
//cout<<ans[7]<<ans[6]<<ans[5]<<ans[4]<<ans[3]<<ans[2]<<ans[1]<<ans[0]<<endl;
idx--;
for (int i = 0; i <= idx / 2; i++) {
char tmp = ans[i];
ans[i] = ans[idx - i];
ans[idx - i] = tmp;
//cout<<ans[7]<<ans[6]<<ans[5]<<ans[4]<<ans[3]<<ans[2]<<ans[1]<<ans[0]<<endl;
}
ans[++idx] = '\0';
//printf("%s\n",ans);
}
三、measure_simple.h
#pragma once
#ifndef MEASURE_SIMPLE_H
#define MEASURE_SIMPLE_H
#endif // MEASURE_SIMPLE_H
#include<opencv2/opencv.hpp>
using namespace cv;
void measure_simple(double &proportion);
void ImgSkeletonization(Mat &input_src, Mat &output_dst, int number = 20);//@param number :表示水平方向和垂直方向上“细化的次数”
void ImgSkeletonization_H(Mat &input_src, int *search_arr);//水平方向细化
void ImgSkeletonization_V(Mat &input_src, int *search_arr);//垂直方向细化
四、measure_simple.cpp
#include<opencv2/opencv.hpp>
#include"transform.h"
#include "measure_simple.h"
using namespace std;
using namespace cv;
static int video_flag = 0;
static void on_mouse(int event, int x, int y, int flags, void*) {
if (event == EVENT_LBUTTONDOWN)
if (video_flag == 0)
video_flag++;
}
void measure_simple(double &proportion) {
Mat frame;
namedWindow("frame");
VideoCapture capture(0);
setMouseCallback("frame", on_mouse);
video_flag = 0;
while (video_flag == 0) {
waitKey(30);
capture >> frame;
imshow("frame", frame);
}
imwrite("F:/src1.jpg", frame);
Mat src = imread("F:/src1.jpg", 0);
threshold(src, src, 100, 255, 0);
Mat dst; ImgSkeletonization(src, dst, 30);
src = dst.clone();
int a = 10, b = 10, c = 10, d = 10;
for (int i = 60; i<420; i++) {
for (int j = 1; j<640; j++) {
if (src.at<uchar>(i, j) == 0) {
a = j;
b = i;
break;
}
}
if (a != 10)break;
}
for (int i = 420; i>60; i--) {
for (int j = 639; j>0; j--) {
if (src.at<uchar>(i, j) == 0) {
c = j;
d = i;
break;
}
}
if (c != 10)break;
}
//circle(src, Point2i(a, b), 10, Scalar::all(0));
//circle(src, Point2i(c, d), 10, Scalar::all(0));
//imshow("src", src);
circle(frame, Point2i(a, b), 10, Scalar::all(0));
circle(frame, Point2i(c, d), 10, Scalar::all(0));
proportion = 10 / sqrt((a - c)*(a - c) + (b - d)*(b - d)); char ppp[20]; DoubleToString(proportion, 2, ppp);
//cout << '(' << a << ',' << b << ')' << ',' << '(' << c << ',' << d << ')' << ',' << proportion << "mm/pix" << endl;
putText(frame, ppp, Point(100, 100), FONT_HERSHEY_PLAIN, 3, Scalar::all(0));
putText(frame, "mm/pix", Point(250, 100), FONT_HERSHEY_PLAIN, 3, Scalar::all(0));
imshow("frame", frame);
waitKey(0);
destroyAllWindows();
}
void ImgSkeletonization(Mat &input_src, Mat & output_dst, int number) {
output_dst = input_src.clone();
int search_array[] = { 0,0,1,1,0,0,1,1,1,1,0,1,1,1,0,1,\
1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,1,\
0,0,1,1,0,0,1,1,1,1,0,1,1,1,0,1,\
1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,1,\
1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,\
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\
1,1,0,0,1,1,0,0,1,1,0,1,1,1,0,1,\
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\
0,0,1,1,0,0,1,1,1,1,0,1,1,1,0,1,\
1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,1,\
0,0,1,1,0,0,1,1,1,1,0,1,1,1,0,1,\
1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,0,\
1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,\
1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,0,\
1,1,0,0,1,1,0,0,1,1,0,1,1,1,0,0,\
1,1,0,0,1,1,1,0,1,1,0,0,1,0,0,0 };
for (size_t i = 0; i < number; i++) {
ImgSkeletonization_H(output_dst, &search_array[0]);
ImgSkeletonization_V(output_dst, &search_array[0]);
}
}
void ImgSkeletonization_H(Mat &input_src, int *search_arr) {
int h = input_src.rows;
int w = input_src.cols;
bool NEXT = true;
for (size_t j = 1; j < w - 1; j++) {//注意边界问题!!!!!!
for (size_t i = 1; i < h - 1; i++) {
if (!NEXT)
NEXT = true;
else {
int judge_value;
if (1 <i < h - 1)
judge_value = input_src.at<uchar>(i - 1, j) + input_src.at<uchar>(i, j) + input_src.at<uchar>(i + 1, j);
else
judge_value = 1;
if (input_src.at<uchar>(i, j) == 0 && judge_value != 0) {
int a[9] = { 1,1,1,1,1,1,1,1,1 };
for (size_t m = 0; m < 3; m++) {
for (size_t n = 0; n < 3; n++) {
if ((0 <= (i - 1 + m) < h) && (0 <= (j - 1 + n) < w) && input_src.at<uchar>(i - 1 + m, j - 1 + n) == 0)
a[m * 3 + n] = 0;
}
}
int sum_value = a[0] * 1 + a[1] * 2 + a[2] * 4 + a[3] * 8 + a[5] * 16 + a[6] * 32 + a[7] * 64 + a[8] * 128;
input_src.at<uchar>(i, j) = search_arr[sum_value] * 255;
if (search_arr[sum_value] == 1)
NEXT = false;
}
}
}
}
}
void ImgSkeletonization_V(Mat &input_src, int *search_arr) {
int h = input_src.rows;
int w = input_src.cols;
bool NEXT = true;
for (size_t i = 1; i < h - 1; i++) {//注意边界问题!!!!!!
for (size_t j = 1; j < w - 1; j++) {
if (!NEXT)
NEXT = true;
else {
int judge_value;
if (1 < j <w - 1)
judge_value = input_src.at<uchar>(i, j - 1) + input_src.at<uchar>(i, j) + input_src.at<uchar>(i, j + 1);
else
judge_value = 1;
if (input_src.at<uchar>(i, j) == 0 && judge_value != 0) {
int a[9] = { 1,1,1,1,1,1,1,1,1 };
for (size_t m = 0; m < 3; m++) {
for (size_t n = 0; n < 3; n++) {
if ((0 <= (i - 1 + m) < h) && (0 <= (j - 1 + n) < w) && input_src.at<uchar>(i - 1 + m, j - 1 + n) == 0)
a[m * 3 + n] = 0;
}
}
int sum_value = a[0] * 1 + a[1] * 2 + a[2] * 4 + a[3] * 8 + a[5] * 16 + a[6] * 32 + a[7] * 64 + a[8] * 128;
input_src.at<uchar>(i, j) = search_arr[sum_value] * 255;
if (search_arr[sum_value] == 1)
NEXT = false;
}
}
}
}
}
五、measure_circle.h
#pragma once
#ifndef MEASURE_CIRCLE_H
#define MEASURE_CIRCLE_H
#endif // MEASURE_CIRCLE_H
void measure_circle(double p);
六、measure_circle.cpp
#include<opencv2/opencv.hpp>
#include"transform.h"
#include<vector>
using namespace std;
using namespace cv;
void measure_circle(double p) {
Mat frame; int key;
namedWindow("frame");
VideoCapture capture(0);
while (1) {
key = waitKey(30);
if (key == ' ')break;
capture >> frame;
imshow("frame", frame);
}
imwrite("F:/src2.jpg", frame);
Mat src = imread("F:/src2.jpg", 0);
GaussianBlur(src, src, Size(9, 9), 2, 2);
vector<Vec3f>circles;
HoughCircles(src, circles, HOUGH_GRADIENT, 1.1, 100, 200, 100, 0, 0);
for (size_t i = 0; i<circles.size(); i++) {
Point center(cvRound(circles[i][0]), cvRound(circles[i][1]));
int radiu = cvRound(circles[i][2]);
circle(frame, center, 3, Scalar(0, 255, 0), -1, 8, 0);
circle(frame, center, radiu, Scalar(155, 50, 255), 3, 8, 0);
double radius = radiu*p;char rrr[20]="0";DoubleToString(radius, 2, rrr);
//cout << '(' << center.x << ',' << center.y << ") " << radiu << "pix " << radiu*p << "mm" << endl;
putText(frame, rrr, Point(100, 100), FONT_HERSHEY_PLAIN, 3, Scalar::all(0));
putText(frame, "mm", Point(250, 100), FONT_HERSHEY_PLAIN, 3, Scalar::all(0));
}
//if (circles.size() == 0)cout << 0 << endl;
imshow("frame", frame);
waitKey(0);
destroyAllWindows();
}
七、measure_rectangle.h
#pragma once
#ifndef MEASURE_RECTANGLE_H
#define MEASURE_RECTANGLE_H
#endif // MEASURE_RECTANGLE_H
void measure_rectangle(double p);
八、measure_rectangle.cpp
#include<opencv2/opencv.hpp>
#include"transform.h"
#include<vector>
using namespace std;
using namespace cv;
void measure_rectangle(double p) {
Mat frame; int key;
namedWindow("frame");
VideoCapture capture(0);
while (1) {
key = waitKey(30);
if (key == ' ')break;
capture >> frame;
imshow("frame", frame);
}
imwrite("F:/src3.jpg", frame);
Mat src = imread("F:/src3.jpg", 0);
vector<Point2f> corners;
goodFeaturesToTrack(src,//输入图像
corners,//检测到的角点的输出向量
4,//角点的最大数量
0.01,//角点检测可接受的最小特征值
10,//角点之间的最小距离
Mat(),//感兴趣区域
3,//计算导数自相关矩阵时指定的邻域范围
false,//不使用Harris角点检测
0.04);//权重系数
double dis[4], min_dis = 100000, mid_dis = 100000; RNG g_rng(12345);
for (unsigned long long i = 0; i < corners.size(); i++) {
cout << corners[i].x << ' ' << corners[i].y << endl;
circle(frame, corners[i], 4, Scalar(g_rng.uniform(0, 255), g_rng.uniform(0, 255), g_rng.uniform(0, 255)), -1, 8, 0);
if (i == 0)continue;
dis[i] = sqrt((corners[i].x - corners[0].x)*(corners[i].x - corners[0].x) + (corners[i].y - corners[0].y)*(corners[i].y - corners[0].y));
if (dis[i]<min_dis) { mid_dis = min_dis; min_dis = dis[i]; }
else if (dis[i]<mid_dis)mid_dis = dis[i];
}
double length = mid_dis*p; char lll[20]; DoubleToString(length, 2, lll);
double width = min_dis*p; char www[20]; DoubleToString(width, 2, www);
//cout << "length: " << mid_dis << "pix," << length << "mm" << endl;
//cout << "width: " << min_dis << "pix," << width << "mm" << endl;
putText(frame, lll, Point(50, 50), FONT_HERSHEY_PLAIN, 3, Scalar::all(0));
putText(frame, "mm", Point(200, 50), FONT_HERSHEY_PLAIN, 3, Scalar::all(0));
putText(frame, www, Point(50, 100), FONT_HERSHEY_PLAIN, 3, Scalar::all(0));
putText(frame, "mm", Point(200, 100), FONT_HERSHEY_PLAIN, 3, Scalar::all(0));
imshow("frame", frame);
waitKey(0);
destroyAllWindows();
}
九、main.h
#include<afxwin.h> //main头文件
class MyApp:public CWinApp { //CWinApp应用程序类
public:
virtual BOOL InitInstance(); //程序入口
};
class MyFrame :public CFrameWnd { //窗口框架类
public:
MyFrame(); //构造函数
DECLARE_MESSAGE_MAP() //声明宏 提供消息映射机制
afx_msg void OnLButtonDown(UINT, CPoint); //鼠标左键消息响应函数
afx_msg void OnChar(UINT, UINT, UINT); //键盘消息响应函数
afx_msg void OnPaint(); //绘画消息响应函数
};
十、main.cpp
#include "main.h" //必须滴,千丝万缕的关系
#include "measure_simple.h" //为了调用标定函数
#include "measure_circle.h" //为了调用测圆函数
#include "measure_rectangle.h" //为了调用测矩函数
MyApp app; //全局应用程序对象,有且仅有一个
BOOL MyApp::InitInstance(){ //程序入口
MyFrame* frame = new MyFrame;//创建窗口
frame->ShowWindow(SW_SHOWNORMAL); //显示
frame->UpdateWindow(); //更新
m_pMainWnd = frame; //保存指向应用程序的主窗口的指针
return TRUE; //返回正常初始化
}
BEGIN_MESSAGE_MAP(MyFrame, CFrameWnd) //分界宏上界
ON_WM_LBUTTONDOWN() //鼠标左键按下
ON_WM_CHAR() //键盘按键按下
ON_WM_PAINT() //绘图宏
END_MESSAGE_MAP() //分界宏下界
MyFrame::MyFrame(){ //构造函数,就是应用程序创建窗口
Create(NULL, TEXT("mfc"));
}
void MyFrame::OnLButtonDown(UINT, CPoint point){ //按下鼠标左键的响应事件(坐标在CPoint point传入)
double proportion = 1.0; //定义比例
if (point.x > 100 && point.x < 300 && point.y>100 && point.y < 200) measure_simple(proportion); //标定比例
if (point.x > 100 && point.x < 300 && point.y>300 && point.y < 400) measure_circle(proportion); //测量半径
if (point.x > 100 && point.x < 300 && point.y>500 && point.y < 600) measure_rectangle(proportion); //测量长宽
}
void MyFrame::OnChar(UINT key, UINT, UINT){ //键盘消息响应函数(键值在UINT key传入)
CString str;str.Format(TEXT("%c"), key);MessageBox(str); //CString形式显示对话框
TCHAR buf[1024]; wsprintf(buf,TEXT("%c"), key); MessageBox(buf); //TCHAR形式显示对话框
}
void MyFrame::OnPaint(){ //绘画消息响应函数(理论上是应该加定时器刷新的,参考JAVA坦克大战多线程)
CPaintDC dc(this); //在CDC里找其他能画的图形
dc.Ellipse(100, 100, 300, 200); //给出左上与右下角画内切椭圆(按钮轮廓)
dc.Ellipse(100, 300, 300, 400); //给出左上与右下角画内切椭圆(按钮轮廓)
dc.Ellipse(100, 500, 300, 600); //给出左上与右下角画内切椭圆(按钮轮廓)
dc.TextOutW(167, 144, TEXT("measure")); //画出(按钮标签)
dc.TextOutW(167, 344, TEXT("circle")); //画出(按钮标签)
dc.TextOutW(167, 544, TEXT("retangle")); //画出(按钮标签)
POINT pt[2]; pt[0].x = 400, pt[1].y = 100; pt[1].x = 400, pt[1].y = 700;dc.Polyline(pt,2);//给出画直线函数
}