发布时间:2022-08-19 13:08
0.代码基本框架
#include
#include
#include
using namespace cv;
using namespace std;
int main(int agrc, char ** agrv)
{
waitKey(0);
return -1;
}
1.调试代码:
#include
#include
using namespace cv;
int main(int agrc, char** agrv)
{
Mat src = imread("C:/Users/25503/Desktop/张教授项目/1.jpg");
if (src.empty())
{
printf("could not load image....\n");
return - 1;
}
namedWindow("test opencv setup", CV_WINDOW_AUTOSIZE);
imshow("test opencv setup", src);
waitKey(0);
return 0;
}
2.加载、修改、保存图像
#include
#include
#include
using namespace cv;
int main(int argc, char** argv)
{
Mat src = imread("C:/Users/25503/Desktop/张教授项目/1.jpg");//读取图像
if (src.empty())
{
printf("could not load image...\n");
return -1;
}
namedWindow("opencv setup demo", CV_WINDOW_AUTOSIZE);//图像显示窗口设置大小
imshow("opencv setup demo", src);//显示图像(原始图像)
namedWindow("output windows", CV_WINDOW_AUTOSIZE);//设置图像显示窗口大小
Mat output_image;
cvtColor(src, output_image, CV_BGR2HLS);//将彩色图像改变成HLS图像
imshow("output windows", output_image);
imwrite("C:/Users/25503/Desktop/张教授项目/1.png",output_image);//保存图像,包括保存类型和路径
waitKey(0);
return 0;
}
3.对比度提高(1)
#include
#include
#include
using namespace cv;
int main(int argc, char** argv)
{
Mat src, dst;
src = imread("C:/Users/25503/Desktop/张教授项目/1.jpg");//读取图像
if (src.empty())
{
printf("could not load image...\n");
return -1;
}
namedWindow("opencv setup demo", CV_WINDOW_AUTOSIZE);//图像显示窗口设置大小
imshow("opencv setup demo", src);//显示图像(原始图像)
int cols = (src.cols - 1)*src.channels();
int offsetx = src.channels();
int rows = src.rows;
dst = Mat::zeros(src.size(), src.type());
for (int row = 1; row < (rows - 1); row++)
{
const uchar* previous = src.ptr
const uchar* current = src.ptr
const uchar* next = src.ptr
uchar* output = dst.ptr
for (int col = offsetx; col < cols; col++)
{
output[col] = saturate_cast
}
}
namedWindow("test opencv setup", CV_WINDOW_AUTOSIZE);
imshow("test opencv setup", dst);
waitKey(0);
return 0;
}
3.对比度提高(2)
#include
#include
#include
using namespace cv;
int main(int argc, char** argv)
{
Mat src, dst;
src = imread("C:/Users/25503/Desktop/张教授项目/1.jpg");//读取图像
if (src.empty())
{
printf("could not load image...\n");
return -1;
}
namedWindow("opencv setup demo", CV_WINDOW_AUTOSIZE);//图像显示窗口设置大小
imshow("opencv setup demo", src);//显示图像(原始图像)
/*int cols = (src.cols - 1)*src.channels();
int offsetx = src.channels();
int rows = src.rows;
dst = Mat::zeros(src.size(), src.type());
for (int row = 1; row < (rows - 1); row++)
{
const uchar* previous = src.ptr
const uchar* current = src.ptr
const uchar* next = src.ptr
uchar* output = dst.ptr
for (int col = offsetx; col < cols; col++)
{
output[col] = saturate_cast
}
}
*/
Mat kernel = (Mat_
filter2D(src, dst, src.depth(), kernel);
namedWindow("test opencv setup", CV_WINDOW_AUTOSIZE);
imshow("test opencv setup", dst);
waitKey(0);
return 0;
}
4.调节图像的对比度和亮度
5.图像模糊
6.视频读写(1)--读取已保存的.mp4文件
#include
#include
using namespace cv;
using namespace std;
int main(int agrc, char** agrv)
{
VideoCapture capture;
capture.open("C:/Users/25503/Desktop/张教授项目/text.mp4");
if (!capture.isOpened())
{
printf("could not load video data....\n");
return -1;
}
Mat frame;
namedWindow("video-demo", CV_WINDOW_AUTOSIZE);
while (capture.read(frame))
{
imshow("video-demo", frame);
char c = waitKey(100);
if (c == 27)
{
break;
}
}
waitKey(0);
return 0;
}
6.视频读写(2)--打开摄像头读取文件.mp4文件
#include
#include
using namespace cv;
using namespace std;
int main(int agrc, char** agrv)
{
VideoCapture capture(0);//打开摄像头
//capture.open("C:/Users/25503/Desktop/张教授项目/text.mp4");//从已保存的文件中读取视频
if (!capture.isOpened())
{
printf("could not load video data....\n");
return -1;
}
Mat frame;
namedWindow("video-demo", CV_WINDOW_AUTOSIZE);
while (capture.read(frame))
{
imshow("video-demo", frame);
char c = waitKey(100);
if (c == 27)
{
break;
}
}
waitKey(0);
return 0;
}
7.基于颜色轨迹跟踪
#include
#include
using namespace std;
using namespace cv;
Rect roi;
void processFrame(Mat &binary, Rect &rect);
int main()
{
// load video
VideoCapture capture;
capture.open("C:/Users/25503/Desktop/张教授项目/text.mp4");
if (!capture.isOpened())
{
printf("could not find video file....\n");
return -1;
}
Mat frame,mask;
Mat kernel1 = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));
Mat kernel2 = getStructuringElement(MORPH_RECT, Size(5, 5), Point(-1, -1));
namedWindow("input video", CV_WINDOW_AUTOSIZE);
namedWindow("track mask", CV_WINDOW_AUTOSIZE);
while (capture.read(frame))
{
inRange(frame, Scalar(0, 127, 0), Scalar(120, 255, 120), mask);//过滤
morphologyEx(mask, mask, MORPH_OPEN, kernel1, Point(-1, -1), 1);//开运算
dilate(mask, mask, kernel2, Point(-1, -1), 4);//膨胀
imshow("track mask", mask);
processFrame(mask, roi);//轮廓发现与位置标定
rectangle(frame, roi, Scalar(0, 0, 255), 3, 8, 0);
imshow("input video", frame);
//trigger exit
char c = waitKey(1);
if (c == 27)
{
break;
}
}
capture.release();
waitKey(0);
return 0;
}
void processFrame(Mat &binary, Rect &rect)
{
vector
vector
findContours(binary, contours, hireachy,RETR_EXTERNAL, CHAIN_APPROX_SIMPLE,Point(0,0));
if (contours.size() > 0)
{
double maxArea = 0.0;
for (size_t t = 0; t < contours.size(); t++)
{
double area = contourArea(contours[static_cast
if (area > maxArea)
{
maxArea = area;
rect = boundingRect(contours[static_cast
}
}
}
else
{
rect.x = rect.y = rect.width = rect.height = 0;
}
}
8.单目标开摄像头跟踪
#include
#include
using namespace std;
using namespace cv;
Rect roi;
void processFrame(Mat &binary, Rect &rect);
int main()
{
// load video
VideoCapture capture(0);//打开摄像头
//VideoCapture capture;
//capture.open("C:/Users/25503/Desktop/张教授项目/text.mp4");
if (!capture.isOpened())
{
printf("could not find video file....\n");
return -1;
}
Mat frame, mask;
Mat kernel1 = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));
Mat kernel2 = getStructuringElement(MORPH_RECT, Size(5, 5), Point(-1, -1));
namedWindow("input video", CV_WINDOW_AUTOSIZE);
namedWindow("track mask", CV_WINDOW_AUTOSIZE);
while (capture.read(frame))
{
inRange(frame, Scalar(220, 220, 220), Scalar(255, 255, 255), mask);//过滤
imshow("track mask1", mask);
morphologyEx(mask, mask, MORPH_OPEN, kernel1, Point(-1, -1), 1);//开运算
dilate(mask, mask, kernel2, Point(-1, -1), 4);//膨胀
imshow("track mask2", mask);
processFrame(mask, roi);//轮廓发现与位置标定
rectangle(frame, roi, Scalar(0, 0, 255), 3, 8, 0);//BGR
imshow("input video", frame);
//trigger exit
char c = waitKey(1);
if (c == 27)
{
break;
}
}
capture.release();
waitKey(0);
return 0;
}
void processFrame(Mat &binary, Rect &rect)
{
vector
vector
findContours(binary, contours, hireachy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE, Point(0, 0));
if (contours.size() > 0)
{
double maxArea = 0.0;
for (size_t t = 0; t < contours.size(); t++)
{
double area = contourArea(contours[static_cast
if (area > maxArea)
{
maxArea = area;
rect = boundingRect(contours[static_cast
}
}
}
else
{
rect.x = rect.y = rect.width = rect.height = 0;
}
}
9.单目标跟踪方法:TrackerKCF速度快、基本好用;TrackerBoosting;TrackerMIL;TrackerMedianFlow;TrackerTLD
#include
#include
#include
using namespace cv;
using namespace std;
int main(int argc, char** argv)
{
VideoCapture capture;
capture.open("C:/Users/25503/Desktop/张教授项目/text.mp4");//读取视频
if (!capture.isOpened())
{
printf("could not load video data....\n");
return -1;
}
Mat frame;
namedWindow("tracker demo", CV_WINDOW_AUTOSIZE);
Ptr
capture.read(frame);
Rect2d roi = selectROI("tracker demo", frame);
if (roi.width == 0 || roi.height == 0)
{
return -1;
}
tracker->init(frame, roi);
while (capture.read(frame))
{
tracker->update(frame, roi);
rectangle(frame, roi, Scalar(255, 0, 0), 2, 8, 0);
imshow("track demo", frame);
char c = waitKey(20);
if (c == 27)
{
break;
}
}
capture.release();
waitKey(0);
return 0;
}
(2)单目标图像跟踪程序
#include
#include
#include
using namespace cv;
using namespace std;
int main(int argc, char** argv)
{
VideoCapture capture(0);//打开摄像头
if (!capture.isOpened())
{
printf("could not load video data....\n");
return -1;
}
Mat frame;
namedWindow("tracker demo", CV_WINDOW_AUTOSIZE);
Ptr
capture.read(frame);
Rect2d roi = selectROI("tracker demo", frame);
if (roi.width == 0 || roi.height == 0)
{
return -1;
}
tracker->init(frame, roi);
while (capture.read(frame))
{
tracker->update(frame, roi);
rectangle(frame, roi, Scalar(255, 0, 0), 2, 8, 0);
imshow("track demo", frame);
char c = waitKey(20);
if (c == 27)
{
break;
}
}
capture.release();
waitKey(0);
return 0;
}
多目标跟踪1*****失败,因为OpenCV 教学视频与自己的版本不同,最终调试好的可参考P123中的(2)
#include
#include
#include
using namespace cv;
using namespace std;
int main(int agrc, char ** agrv)
{
VideoCapture capture;
capture.open("C:/Users/25503/Desktop/张教授项目/text.mp4");
if (!capture.isOpened())
{
printf("could not load data....\n");
return -1;
}
namedWindow("Multiple Objects Tracking", CV_WINDOW_AUTOSIZE);
Ptr
vector
Mat frame, gray;
capture.read(frame);
selectROIs("Multiple Object Tracking", frame, objects);
if (objects.size() < 1)
{
return -1;
}
trackers.add(frame, objects);
while (capture.read(frame))
{
trackers.update(frame);
for (size_t t = 0; t < trackers.getObjects.size(); t++)
{
rectangle(frame, trackers.objects[t], Scalar(0, 0, 255), 2, 8, 0);
}
imshow("Multiple Objects Tracking", frame);
char c = waitKey(50);
if (c == 27)
{
break;
}
}
capture.release();
waitKey(0);
return -1;
}
单目标跟踪
#include
bool selectObject = false; //用于是否有选取目标
int trackObject = 0; // 1表示有追踪对象 0 表示无追踪对象
//-1表示追踪对象尚未计算camshift所需的属性
cv::Rect selection;//保存鼠标选择的区域
cv::Mat image;//用于缓存读取到的视频帧
/*
opencv 对所注册的鼠标回调函数定义为:
void onMouse(int event,int x,int y,int flag,void * param)
其中第四个flag为event下的附加状态,param是用户传入的参数
*/
void onMouse( int event, int x, int y, int, void* ) {
static cv::Point origin;
/*static关键字的作用:
1、隐藏功能 利用这一特性可以在不同的文件中定义同名函数和同名变量
2、保持变量内容的持久
*/
if(selectObject) {//如果检测到选取目标进行下面的操作
//确定鼠标选定区域的左上角坐标以及区域的长和宽
selection.x = MIN(x, origin.x);
selection.y = MIN(y, origin.y);
selection.width = std::abs(x - origin.x);
selection.height = std::abs(y - origin.y);
//&运算符被cv::Rect进行重载
//表示两个区域的交集,主要目的是为了处理当鼠标在选择区域时移除画面外
selection &= cv::Rect(0, 0, image.cols, image.rows);
}
switch(event) {
//处理鼠标左键被按下
case CV_EVENT_LBUTTONDOWN:
origin = cv::Point(x, y);
selection = cv::Rect(x, y, 0, 0);
selectObject = true;
break;
//处理鼠标左键被抬起
case CV_EVENT_LBUTTONUP:
selectObject = false;
if( selection.width > 0 && selection.height > 0 )
trackObject = -1;//追踪的目标还未计算camshift所需要的属性
break;
}
}
int main( int argc, const char** argv )
{
cv::VideoCapture video("video.ogv");//读取文件
//如果需要使用摄像头则代码为
//cv::VideoCapture video(0);
cv::namedWindow( "test" );
//注册鼠标事件的回调函数,第三个参数是用户提供给回掉函数的
//也就是回调函数中最后的param参数
cv::setMouseCallback( "test", onMouse, 0 );
/*
捕获画面的容器,opencv中的mat对象
opencv中最关键的mat类,mat是matrix的缩写
opencv中延续了像素图的概念,用矩阵来描述由像素构成的图像
*/
cv::Mat frame, hsv, hue, mask, hist, backproj;
cv::Rect trackWindow; //追踪到的窗口
int hsize = 16;//计算直方图所必备的内容
float hranges[] = {0,180};//计算直方图所必备的内容
const float* phranges = hranges;//计算直方图所必备的内容
while(true) {
//将video中的内容写入到frame中,
//这里的>>运算符是经过opencv重载的
video >> frame;
if( frame.empty() )//没有帧可以读取的时候,退出循环
break;
//将frame中的图像写入全局变量image作为进行camshift的缓存
frame.copyTo(image);
//转换到的HSV空间
cv::cvtColor(image, hsv, cv::COLOR_BGR2HSV);
//当有目标时候进行处理
if( trackObject ) {
// 只处理像素值为H:0~180,S:30~256,V:10~256之间的部分,过滤掉其他的部分并复制给 mask
cv::inRange(hsv, cv::Scalar(0, 30, 10), cv::Scalar(180, 256, 256), mask);
//下面三句将hsv图像中的H通道分离出来
int ch[] = {0, 0};
hue.create(hsv.size(), hsv.depth());
cv::mixChannels(&hsv, 1, &hue, 1, ch, 1);
//如果需要追踪的物体还没有进行属性提取,则对选择的目标中的图像属性提取
if( trackObject < 0 ) {
//设置H通道和mask图像的ROI
cv::Mat roi(hue, selection), maskroi(mask, selection);
//计算ROI所在区域的直方图
calcHist(&roi, 1, 0, maskroi, hist, 1, &hsize, &phranges);
//将直方图归一
normalize(hist, hist, 0, 255, CV_MINMAX);
//设置追踪的窗口
trackWindow = selection;
//标记追踪的目标已经计算过直方图属性
trackObject = 1;
}
//将直方图进行反向投影
calcBackProject(&hue, 1, 0, hist, backproj, &phranges);
//取公共部分
backproj &= mask;
//调用camshift算法的接口
cv::RotatedRect trackBox = CamShift(backproj, trackWindow, cv::TermCriteria( CV_TERMCRIT_EPS | CV_TERMCRIT_ITER, 10, 1 ));
//处理追踪面积过小的情况
if( trackWindow.area() <= 1 ) {
int cols = backproj.cols, rows = backproj.rows, r = (MIN(cols, rows) + 5)/6;
trackWindow = cv::Rect(trackWindow.x - r, trackWindow.y - r,
trackWindow.x + r, trackWindow.y + r) &
cv::Rect(0, 0, cols, rows);
}
//绘制追踪区域
ellipse( image, trackBox, cv::Scalar(0,0,255), 3, CV_AA );
}
//如果正在选择追踪目标,则画出选择框
if( selectObject && selection.width > 0 && selection.height > 0 ) {
cv::Mat roi(image, selection);
bitwise_not(roi, roi);//对选择的区域图像反色
}
imshow( "test", image );//显示当前帧
// 录制视频帧率为 15, 等待 1000/15 保证视频播放流畅。
// waitKey(int delay) 是 OpenCV 提供的一个等待函数,
// 当运行到这个函数时会阻塞 delay 毫秒的时间来等待键盘输入
char c = (char)cv::waitKey(1000/15.0);
if( c == 27 )//当按键为esc时,退出循环
break;
}
//释放申请的相关内存
cv::destroyAllWindows();
video.release();
return 0;
}
/*以下为本程序仿真步骤
需要安装opencv、opengl
提供linux环境下安装opencv的方法
sudo apt-get install libopencv-dev
linux环境安装opengl的命令
//sudo apt-get update && sudo apt-get install freeglut3 freeglut3-dev
另外提供安装linux环境下的屏幕录制工具
sudo apt-get update && sudo apt-get install gtk-recordmydesktop
linux环境下编译命令
g++ main.cpp `pkg-config opencv --libs --cflags opencv` -o main
*/
2多目标跟踪
// Opencv_MultiTracker.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include
#include
#include
using namespace cv;
using namespace std;
vector
/**
* @brief Create a Tracker By Name object 根据设定的类型初始化跟踪器
*
* @param trackerType
* @return Ptr
*/
Ptr
{
Ptr
if (trackerType == trackerTypes[0])
tracker = TrackerBoosting::create();
else if (trackerType == trackerTypes[1])
tracker = TrackerMIL::create();
else if (trackerType == trackerTypes[2])
tracker = TrackerKCF::create();
else if (trackerType == trackerTypes[3])
tracker = TrackerTLD::create();
else if (trackerType == trackerTypes[4])
tracker = TrackerMedianFlow::create();
else if (trackerType == trackerTypes[5])
tracker = TrackerGOTURN::create();
else if (trackerType == trackerTypes[6])
tracker = TrackerMOSSE::create();
else if (trackerType == trackerTypes[7])
tracker = TrackerCSRT::create();
else
{
cout << "Incorrect tracker name" << endl;
cout << "Available trackers are: " << endl;
for (vector
{
std::cout << " " << *it << endl;
}
}
return tracker;
}
/**
* @brief Get the Random Colors object 随机涂色
*
* @param colors
* @param numColors
*/
void getRandomColors(vector
{
RNG rng(0);
for (int i = 0; i < numColors; i++)
{
colors.push_back(Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255)));
}
}
int main(int argc, char *argv[])
{
// Set tracker type. Change this to try different trackers. 选择追踪器类型
string trackerType = trackerTypes[7];
// set default values for tracking algorithm and video 视频读取
//string videoPath = "video/run.mp4";
VideoCapture cap(0);//打开摄像头
// Initialize MultiTracker with tracking algo 边界框
vector
// create a video capture object to read videos 读视频
//cv::VideoCapture cap(videoPath);
Mat frame;
// quit if unable to read video file
if (!cap.isOpened())
{
printf("could not load video data....\n");
return -1;
}
// read first frame 读第一帧
cap >> frame;
// draw bounding boxes over objects 在第一帧内确定对象框
/*
先在图像上画框,然后按ENTER确定画下一个框。按ESC退出画框开始执行程序
*/
cout << "\n==========================================================\n";
cout << "OpenCV says press c to cancel objects selection process" << endl;
cout << "It doesn't work. Press Esc to exit selection process" << endl;
cout << "\n==========================================================\n";
cv::selectROIs("MultiTracker", frame, bboxes, false);
//自己设定对象的检测框
//x,y,width,height
//bboxes.push_back(Rect(388, 155, 30, 40));
//bboxes.push_back(Rect(492, 205, 50, 80));
// quit if there are no objects to track 如果没有选择对象
if (bboxes.size() < 1)
{
return 0;
}
vector
//给各个框涂色
getRandomColors(colors, bboxes.size());
// Create multitracker 创建多目标跟踪类
Ptr
// initialize multitracker 初始化
for (int i = 0; i < bboxes.size(); i++)
{
multiTracker->add(createTrackerByName(trackerType), frame, Rect2d(bboxes[i]));
}
// process video and track objects 开始处理图像
cout << "\n==========================================================\n";
cout << "Started tracking, press ESC to quit." << endl;
while (cap.isOpened())
{
// get frame from the video 逐帧处理
cap >> frame;
// stop the program if reached end of video
if (frame.empty())
{
break;
}
//update the tracking result with new frame 更新每一帧
bool ok = multiTracker->update(frame);
if (ok == true)
{
cout << "Tracking success" << endl;
}
else
{
cout << "Tracking failure" << endl;
}
// draw tracked objects 画框
for (unsigned i = 0; i < multiTracker->getObjects().size(); i++)
{
rectangle(frame, multiTracker->getObjects()[i], colors[i], 2, 1);
}
// show frame
imshow("MultiTracker", frame);
// quit on x button
if (waitKey(1) == 27)
{
break;
}
}
waitKey(0);
return 0;
}
P09模糊图像//2021/1/5 均值模糊和高斯模糊
# include
# include
using namespace cv;
int main(int argc, char** agrv)
{
Mat src, dst;
src = imread("C:/Users/25503/Desktop/张教授项目/1.jpg");
if (!src.data)
{
printf("could not load image...\n");
return -1;
}
char input_title[] = "input image";
char output_title[] = "blur image";
namedWindow(input_title, CV_WINDOW_AUTOSIZE);
namedWindow(output_title, CV_WINDOW_AUTOSIZE);
imshow(input_title, src);
blur(src, dst, Size(9, 3), Point(-1, -1));//均值模糊
imshow(output_title, dst);
Mat gblur;
GaussianBlur(src, gblur, Size(9, 3), 11, 11);//高斯模糊
imshow("gaussian blur", gblur);
waitKey(0);
return 0;
}
P10中值滤波(对椒盐噪声抑制很好)、高斯双边滤波(能够很好的保留图像边缘信息)***
# include
# include
using namespace cv;
int main(int argc, char** agrv)
{
Mat src, dst;
src = imread("C:/Users/25503/Desktop/张教授项目/1.jpg");
if (!src.data)
{
printf("could not load image...\n");
return -1;
}
namedWindow("input_title", CV_WINDOW_AUTOSIZE);
imshow("input_title", src);
//medianBlur(src, dst, 3)
bilateralFilter(src, dst, 15, 100, 5);
namedWindow("BiBlur Filter result", CV_WINDOW_AUTOSIZE);
imshow("BiBlur Filter result", dst);
Mat resultImg;
Mat kernel = (Mat_
filter2D(dst, resultImg, -1, kernel, Point(-1, -1), 0);
imshow("Final result", resultImg);
waitKey(0);
return 0;
}
P11膨胀与腐蚀
# include
# include
using namespace cv;
Mat src, dst;
char OUTPUT_WIN[] = "output image";
int element_size = 3;
int max_size = 21;
void CallBack_Demo(int, void*);
int main(int argc, char** agrv)
{
src = imread("C:/Users/25503/Desktop/张教授项目/1.jpg");
if (!src.data)
{
printf("could not load image...\n");
return -1;
}
namedWindow("input_title", CV_WINDOW_AUTOSIZE);
imshow("input_title", src);
namedWindow(OUTPUT_WIN, CV_WINDOW_AUTOSIZE);
createTrackbar("Element Size:", OUTPUT_WIN, &element_size, max_size, CallBack_Demo);
CallBack_Demo(0, 0);
waitKey(0);
return 0;
}
void CallBack_Demo(int, void*)
{
int s = element_size * 2 + 1;
Mat structureElement = getStructuringElement(MORPH_RECT, Size(5, 5), Point(-1, -1));//Size(x,y)中的x,y可以调节
dilate(src, dst, structureElement, Point(-1, -1), 1);//膨胀
//erode(src, dst, structureElement);//腐蚀
imshow(OUTPUT_WIN, dst);
return;
}
P12形态学操作2021/1/6
开操作open、闭操作close、形态学梯度、顶帽top_hat、黑帽
# include
# include
using namespace cv;
int main(int argc, char** agrv)
{
Mat src, dst;
src = imread("C:/Users/25503/Desktop/张教授项目/1.jpg");
if (!src.data)
{
printf("could not load image...\n");
return -1;
}
namedWindow("input_title", CV_WINDOW_AUTOSIZE);
imshow("input_title", src);
char out_title[] = "morphology demo";
namedWindow(out_title, CV_WINDOW_AUTOSIZE);
Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));
//morphologyEx(src, dst, CV_MOP_OPEN, kernel);//先腐蚀后膨胀,可以去掉小的对象,假设对象是前景色,背景是黑色
//morphologyEx(src, dst, CV_MOP_CLOSE, kernel);//先膨胀后腐蚀,可以填充小的洞,假设对象是前景色,背景是黑色
//morphologyEx(src, dst, CV_MOP_GRADIENT, kernel);//膨胀减去腐蚀
//morphologyEx(src, dst, CV_MOP_TOPHAT, kernel);//顶帽是原图像与开操作之间的差值图像
morphologyEx(src, dst, CV_MOP_BLACKHAT, kernel);//黑帽是闭操作图像与源图像的差值图像
imshow(out_title, dst);
waitKey(0);
return 0;
}
P13形态学操作-提取水平线、竖直线、字母*******
# include
# include
using namespace cv;
int main(int argc, char** agrv)
{
Mat src, dst;
src = imread("C:/Users/25503/Desktop/124.png");
if (!src.data)
{
printf("could not load image...\n");
return -1;
}
char INPUT_WIN[] = "input image";
char OUTPUT_WIN[] = "result image";
namedWindow(INPUT_WIN, CV_WINDOW_AUTOSIZE);
imshow(INPUT_WIN, src);
Mat gray_src;
cvtColor(src, gray_src, CV_BGR2GRAY);//彩色图转换为灰度图
imshow("gray image", gray_src);
Mat binImg;
adaptiveThreshold(gray_src, binImg, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, 15, -2);//灰度图转换为二值图
imshow("binary image", binImg);
Mat hline = getStructuringElement(MORPH_RECT, Size(src.cols / 16, 1), Point(-1, -1));//定义水平线提取元素
Mat vline = getStructuringElement(MORPH_RECT, Size(1, src.cols / 16), Point(-1, -1));//定义数值线提取元素
Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));//矩形元素提取
/*读取直线或者竖直线操作*/
Mat temp_h;
//erode(binImg, temp_h, hline);//腐蚀
//dilate(temp_h, dst, hline);//膨胀
morphologyEx(binImg, dst, CV_MOP_OPEN, hline);//开操作相当于先腐蚀后膨胀
bitwise_not(dst, dst);//背景色取反,即背景色白色转换为黑色;背景色为白色转换为白色
blur(dst, dst, Size(3, 3), Point(-1, -1));//让输出结果更加好看
imshow("Final Result hline", dst);//得到水平线
/*读取直线或者竖直线操作*/
Mat temp_v;
erode(binImg, temp_v, vline);//腐蚀
dilate(temp_v, dst, vline);//膨胀
bitwise_not(dst, dst);//背景色取反,即背景色白色转换为黑色;背景色为白色转换为白色
blur(dst, dst, Size(3, 3), Point(-1, -1));//让输出结果更加好看
imshow("Final Result vline", dst);//得到水平线
/*矩形元素提取*/
Mat temp_JuXing;
erode(binImg, temp_JuXing, kernel);//腐蚀
dilate(temp_JuXing, dst, kernel);//膨胀
bitwise_not(dst, dst);//背景色取反,即背景色白色转换为黑色;背景色为白色转换为白色
//blur(dst, dst, Size(3, 3), Point(-1, -1));//让输出结果更加好看
imshow("Final Result Juxing", dst);//得到矩形
waitKey(0);
return 0;
}
P14图像金字塔-上采样与下采样
# include
# include
# include
using namespace cv;
int main(int argc, char** agrv)
{
Mat src, dst;
src = imread("C:/Users/25503/Desktop/124.png");
if (!src.data)
{
printf("could not load image...\n");
return -1;
}
char INPUT_WIN[] = "input image";
char OUTPUT_WIN[] = "result image";
namedWindow(INPUT_WIN, CV_WINDOW_AUTOSIZE);
namedWindow(OUTPUT_WIN, CV_WINDOW_AUTOSIZE);
imshow(INPUT_WIN, src);
//上采样表示图像比原来图像宽高增大2倍或者几倍
pyrUp(src, dst, Size(src.cols * 2, src.rows * 2));
imshow(OUTPUT_WIN, dst);
//下采样表示图像比原来图像宽高缩小2倍或者几倍
Mat s_down;
pyrDown(src, s_down, Size(src.cols / 2, src.rows / 2));
imshow("sample down", s_down);
//高斯不同DOG******
Mat gray_src, g1, g2, dogImg;
cvtColor(src, gray_src, CV_BGR2GRAY);//RGB彩色图像转换为灰度图像
GaussianBlur(gray_src, g1, Size(3, 3), 0, 0);//高斯模糊得到g1
GaussianBlur(g1, g2, Size(3, 3), 0, 0);//再次高斯模糊得到g2
subtract(g1, g2, dogImg, Mat());//从g1中减去g2,得到dogImg
normalize(dogImg, dogImg, 255, 0, NORM_MINMAX);
imshow("DOG Image", dogImg);
waitKey(0);
return 0;
}
P15基本阈值操作
# include
# include
# include
using namespace cv;
Mat src, gray_src, dst;
int threshold_value = 127;
int threshold_max = 255;
const char* output_title = "binary image";
void Threshold_Demo(int, void*);
int main(int argc, char** agrv)
{
src = imread("C:/Users/25503/Desktop/124.png");
if (!src.data)
{
printf("could not load image...\n");
return -1;
}
namedWindow("input image", CV_WINDOW_AUTOSIZE);
namedWindow(output_title, CV_WINDOW_AUTOSIZE);
imshow("input image", src);
cvtColor(src, gray_src, CV_BGR2GRAY);
createTrackbar("Threshold Value:", output_title, &threshold_value, threshold_max, Threshold_Demo);
Threshold_Demo(0, 0);
waitKey(0);
return 0;
}
void Threshold_Demo(int, void*)
{
cvtColor(src, gray_src, CV_BGR2GRAY);//彩色图像转换为灰度图像
threshold(gray_src, dst, threshold_value, threshold_max, THRESH_BINARY);//正常阈值分割,背景为白色,还有其他阈值方法
threshold(gray_src, dst, threshold_value, threshold_max, THRESH_BINARY_INV);//反阈值分割,背景为黑色
imshow(output_title, dst);
}
P16自定义滤波(Robat算子、索贝尔算子、拉布拉斯算子、自定义卷积模糊)
# include
# include
# include
using namespace cv;
int main(int argc, char** agrv)
{
Mat src, dst;
Mat kernel;
int ksize = 0;
Mat s_down;
src = imread("C:/Users/25503/Desktop/张教授项目/1.jpg");
if (!src.data)
{
printf("could not load image...\n");
return -1;
}
char INPUT_WIN[] = "input image";
char OUTPUT_WIN[] = "result image";
namedWindow(INPUT_WIN, CV_WINDOW_AUTOSIZE);
namedWindow(OUTPUT_WIN, CV_WINDOW_AUTOSIZE);
pyrDown(src, s_down, Size(src.cols / 2, src.rows / 2));//缩小显示窗口
imshow(INPUT_WIN, s_down);
//Robert X方向滤波
Mat kernel_x = (Mat_
filter2D(src, dst, -1, kernel_x, Point(-1, -1), 0.0);
pyrDown(dst, s_down, Size(src.cols / 2, src.rows / 2));//缩小显示窗口
imshow("Robert X方向", s_down);
//Robert Y方向滤波
Mat ying;
Mat kernel_y = (Mat_
filter2D(src, ying, -1, kernel_y, Point(-1, -1), 0.0);
pyrDown(ying, s_down, Size(src.cols / 2, src.rows / 2));//缩小显示窗口
imshow("Robert Y方向", s_down);
//Sobel X方向滤波
Mat sobel_x;
Mat kernel_xx = (Mat_
filter2D(src, sobel_x, -1, kernel_xx, Point(-1, -1), 0.0);
pyrDown(sobel_x, s_down, Size(src.cols / 2, src.rows / 2));//缩小显示窗口
imshow("Sobel X方向", s_down);
//Sobel Y方向滤波
Mat sobel_y;
Mat kernel_yy = (Mat_
filter2D(src, sobel_y, -1, kernel_yy, Point(-1, -1), 0.0);
pyrDown(sobel_y, s_down, Size(src.cols / 2, src.rows / 2));//缩小显示窗口
imshow("Sobel Y方向", s_down);
//拉普拉斯算子滤波
Mat LOG_y;
Mat kernel_LOG = (Mat_
filter2D(src, LOG_y, -1, kernel_LOG, Point(-1, -1), 0.0);
pyrDown(LOG_y, s_down, Size(src.cols / 2, src.rows / 2));//缩小显示窗口
imshow("拉普拉斯算子滤波", s_down);
/* //自定义滤波
int c = 0;
int index = 0;
Mat dst_z;
while (true)
{
c = waitKey(500);
if ((char)c == 27)//ESC键
{
break;
}
ksize = 4 + (index % 8) * 2 + 1;
Mat kernel_z = Mat::ones(Size(ksize, ksize), CV_32F) / (float)(ksize *ksize);
filter2D(src, dst_z, -1, kernel_z, Point(-1, -1));
index++;
//imshow("自定义滤波", dst_z);
}
*/
waitKey(0);
return 0;
}
P17 图片边框效果处理
# include
# include
# include
using namespace cv;
int main(int argc, char** agrv)
{
Mat src, dst;
src = imread("C:/Users/25503/Desktop/张教授项目/1.jpg");
if (!src.data)
{
printf("could not load image...\n");
return -1;
}
char INPUT_WIN[] = "input image";
char OUTPUT_WIN[] = "Border Demo";
namedWindow(INPUT_WIN, CV_WINDOW_AUTOSIZE);
namedWindow(OUTPUT_WIN, CV_WINDOW_AUTOSIZE);
imshow(INPUT_WIN, src);
int top = (int)(0.05*src.rows);
int bottom = (int)(0.05*src.rows);
int left = (int)(0.05*src.cols);
int right = (int)(0.05*src.cols);
RNG rng(12345);
int borderType = BORDER_DEFAULT;
int c = 0;
while (true)
{
c = waitKey(500);
if ((char)c == 27)//ESC键
{
break;
}
if ((char)c == 'r')//r键
{
borderType = BORDER_REPLICATE;
}
else if ((char)c == 'v')//v键
{
borderType = BORDER_WRAP;
}
else if ((char)c == 'c')//c键,效果很漂亮
{
borderType = BORDER_CONSTANT;
}
Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
copyMakeBorder(src, dst, top, bottom, left, right, borderType, color);
imshow(OUTPUT_WIN, dst);
}
waitKey(0);
return 0;
}
P18 Sobel算子、Scharr算子边缘检测
# include
# include
# include
using namespace cv;
int main(int argc, char** agrv)
{
Mat src, dst;
Mat s_down;
src = imread("C:/Users/25503/Desktop/张教授项目/1.jpg");
if (!src.data)
{
printf("could not load image...\n");
return -1;
}
char INPUT_WIN[] = "input image";
char OUTPUT_WIN[] = "sobel-Demo";
namedWindow(INPUT_WIN, CV_WINDOW_AUTOSIZE);
//namedWindow(OUTPUT_WIN, CV_WINDOW_AUTOSIZE);
pyrDown(src, s_down, Size(src.cols / 2, src.rows / 2));//缩小显示窗口
imshow(INPUT_WIN, s_down);
Mat gray_src;
GaussianBlur(src, dst, Size(3, 3), 0, 0);
cvtColor(dst, gray_src, CV_BGR2GRAY);//将彩色图像转换为灰度图像
pyrDown(gray_src, s_down, Size(src.cols / 2, src.rows / 2));//缩小显示窗口
imshow("灰度图像", s_down);
Mat xgrad, ygrad;//x,y方向上的sobel边缘检测
Sobel(gray_src, xgrad, CV_16S, 1, 0, 3);
Sobel(gray_src, ygrad, CV_16S, 0, 1, 3);
convertScaleAbs(xgrad, xgrad);
convertScaleAbs(ygrad, ygrad);
pyrDown(xgrad, s_down, Size(src.cols / 2, src.rows / 2));//缩小显示窗口
imshow("xSobel算子结果", s_down);
pyrDown(ygrad, s_down, Size(src.cols / 2, src.rows / 2));//缩小显示窗口
imshow("ySobel算子结果", s_down);
Mat xygrad = Mat(xgrad.size(), xgrad.type());
int width = xgrad.cols;
int height = ygrad.rows;
for (int row = 0; row < height; row++)
{
for (int col = 0; col < width; col++)
{
int xg = xgrad.at
int yg = ygrad.at
int xy = xg + yg;
xygrad.at
}
}
addWeighted(xgrad, 0.5, ygrad, 0.5, 0, xygrad);
pyrDown(xygrad, s_down, Size(src.cols / 2, src.rows / 2));//缩小显示窗口
imshow("xySobel算子结果", s_down);//x和y共同方向上的sobel,也即xygrad
Mat x_grad, y_grad;//x,y方向上的Scharr边缘检测
Scharr(gray_src, x_grad, CV_16S, 1, 0, 3);
Scharr(gray_src, y_grad, CV_16S, 0, 1, 3);
convertScaleAbs(x_grad, x_grad);
convertScaleAbs(y_grad, y_grad);
pyrDown(x_grad, s_down, Size(src.cols / 2, src.rows / 2));//缩小显示窗口
imshow("xScharr算子结果", s_down);
pyrDown(y_grad, s_down, Size(src.cols / 2, src.rows / 2));//缩小显示窗口
imshow("yScharr算子结果", s_down);
Mat xy_grad = Mat(x_grad.size(), x_grad.type());
int width_ = x_grad.cols;
int height_ = y_grad.rows;
for (int row = 0; row < height_; row++)
{
for (int col = 0; col < width_; col++)
{
int x_g = x_grad.at
int y_g = y_grad.at
int x_y = x_g + y_g;
xy_grad.at
}
}
addWeighted(x_grad, 0.5, y_grad, 0.5, 0, xy_grad);
pyrDown(xy_grad, s_down, Size(src.cols / 2, src.rows / 2));//缩小显示窗口
imshow("xyScharr算子结果", s_down);//x和y共同方向上的Scharr,也即xyScharr
waitKey(0);
return 0;
}
P19拉普拉斯边缘检测算子2021/1/6
# include
# include
# include
using namespace cv;
int main(int argc, char** agrv)
{
Mat src, dst;
Mat s_down;
src = imread("C:/Users/25503/Desktop/张教授项目/1.jpg");
if (!src.data)
{
printf("could not load image...\n");
return -1;
}
char INPUT_WIN[] = "input image";
//char OUTPUT_WIN[] = "Laplaiane Result";
namedWindow(INPUT_WIN, CV_WINDOW_AUTOSIZE);
//namedWindow(OUTPUT_WIN, CV_WINDOW_AUTOSIZE);
pyrDown(src, s_down, Size(src.cols / 2, src.rows / 2));//缩小显示窗口
imshow(INPUT_WIN, s_down);
Mat gray_src, edge_image;
GaussianBlur(src, dst, Size(3, 3), 0, 0);//高斯滤波
cvtColor(dst, gray_src, CV_BGR2GRAY);//将彩色图像转换成灰度图像
Laplacian(gray_src, edge_image, CV_16S, 3);//拉普拉斯检测
convertScaleAbs(edge_image, edge_image);//取绝对值
pyrDown(edge_image, s_down, Size(src.cols / 2, src.rows / 2));//缩小显示窗口
imshow("单纯的拉普拉斯边缘检测", s_down);
threshold(edge_image, edge_image, 0, 255, THRESH_OTSU | THRESH_BINARY);//阈值操作
namedWindow("阈值后的拉普拉斯边缘检测", CV_WINDOW_AUTOSIZE);
pyrDown(edge_image, s_down, Size(src.cols / 2, src.rows / 2));//缩小显示窗口
imshow("阈值后的拉普拉斯边缘检测", s_down);
waitKey(0);
return 0;
}
20 Canny算子边缘检测
# include
# include
# include
using namespace cv;
Mat src, dst;
Mat s_down;
Mat gray_src;
int t1_value = 50;
int max_value = 255;
const char* OUTPUT_TITLE = "Canny Result";
void Canny_Demo(int, void*);
int main(int argc, char** agrv)
{
src = imread("C:/Users/25503/Desktop/张教授项目/1.jpg");
if (!src.data)
{
printf("could not load image...\n");
return -1;
}
char INPUT_TITLE[] = "input image";
namedWindow(INPUT_TITLE, CV_WINDOW_AUTOSIZE);
namedWindow(OUTPUT_TITLE, CV_WINDOW_AUTOSIZE);
imshow(INPUT_TITLE, src);
cvtColor(src, gray_src, CV_BGR2GRAY);
createTrackbar("Threshold Value:", OUTPUT_TITLE, &t1_value, max_value, Canny_Demo);
Canny_Demo(0, 0);
waitKey(0);
return 0;
}
void Canny_Demo(int, void*)
{
Mat edge_output;
blur(gray_src, gray_src, Size(3, 3), Point(-1, -1), BORDER_DEFAULT);
Canny(gray_src, edge_output, t1_value, t1_value * 2, 3, false);
dst.create(src.size(), src.type());
src.copyTo(dst, edge_output);
imshow(OUTPUT_TITLE, dst);
}
P21霍夫变换-直线
# include
# include
# include
using namespace cv;
using namespace std;
int main(int argc, char** agrv)
{
Mat src, src_gray, dst;
src = imread("C:/Users/25503/Desktop/555.png");
if (!src.data)
{
printf("could not load image...\n");
return -1;
}
char INPUT_TITLE[] = "input image";
char OUTPUT_TITLE[] = "hough-line-detection";
namedWindow(INPUT_TITLE, CV_WINDOW_AUTOSIZE);
namedWindow(OUTPUT_TITLE, CV_WINDOW_AUTOSIZE);
imshow(INPUT_TITLE, src);
//extract edge
Canny(src, src_gray, 150, 200);
cvtColor(src_gray, dst, CV_GRAY2BGR);
imshow("edge image", src_gray);
vector
HoughLinesP(src_gray, plines, 1, CV_PI / 180.0, 10, 0, 10);//直线检测
Scalar color = Scalar(0, 0, 255);//直线标记红色
for (size_t i = 0; i < plines.size(); i++)
{
Vec4f hline = plines[i];
line(dst, Point(hline[0], hline[1]), Point(hline[2], hline[3]), color, 3, LINE_AA);
}
imshow(OUTPUT_TITLE, dst);
waitKey(0);
return 0;
}
P22霍夫圆变换
# include
# include
# include
using namespace cv;
using namespace std;
int main(int argc, char** agrv)
{
Mat src, src_gray, dst;
src = imread("C:/Users/25503/Desktop/666.png");
if (!src.data)
{
printf("could not load image...\n");
return -1;
}
char INPUT_TITLE[] = "input image";
char OUTPUT_TITLE[] = "hough-circle-detection";
namedWindow(INPUT_TITLE, CV_WINDOW_AUTOSIZE);
namedWindow(OUTPUT_TITLE, CV_WINDOW_AUTOSIZE);
imshow(INPUT_TITLE, src);
//中值滤波
Mat noutput;
medianBlur(src, noutput, 3);
cvtColor(noutput, noutput, CV_BGR2GRAY);
//霍夫圆检测
vector
HoughCircles(noutput, pcircles, CV_HOUGH_GRADIENT, 1, 10, 100, 30, 5, 50);
src.copyTo(dst);
for (size_t i = 0; i < pcircles.size(); i++)
{
Vec3f cc = pcircles[i];
circle(dst, Point(cc[0], cc[1]), cc[2], Scalar(0, 0, 255), 2, LINE_AA);
circle(dst, Point(cc[0], cc[1]), 2, Scalar(198, 23, 155), 2, LINE_AA);
}
imshow(OUTPUT_TITLE, dst);
waitKey(0);
return 0;
}
P23像素重映射(cv_remap)左边的跑到右边,右边的跑到左边
P24直方图均衡化(提高图像对比度)
# include
# include
# include
using namespace cv;
int main(int argc, char** agrv)
{
Mat src, src_gray, dst;
src = imread("C:/Users/25503/Desktop/666.png");
if (!src.data)
{
printf("could not load image...\n");
return -1;
}
cvtColor(src, src, CV_BGR2GRAY);
equalizeHist(src, dst);
char INPUT_TITLE[] = "input image";
char OUTPUT_TITLE[] = "hough-circle-detection";
namedWindow(INPUT_TITLE, CV_WINDOW_AUTOSIZE);
namedWindow(OUTPUT_TITLE, CV_WINDOW_AUTOSIZE);
imshow(INPUT_TITLE, src);
imshow(OUTPUT_TITLE, dst);
waitKey(0);
return 0;
}
P25直方图的计算
# include
# include
# include
using namespace std;
using namespace cv;
int main(int argc, char** agrv)
{
Mat src;
src = imread("C:/Users/25503/Desktop/张教授项目/1.jpg");
if (!src.data)
{
printf("could not load image...\n");
return -1;
}
char INPUT_TITLE[] = "input image";
char OUTPUT_TITLE[] = "historgram-demo";
namedWindow(INPUT_TITLE, CV_WINDOW_AUTOSIZE);
namedWindow(OUTPUT_TITLE, CV_WINDOW_AUTOSIZE);
imshow(INPUT_TITLE, src);
//分通道显示
vector
split(src, bgr_planes);
imshow("single channel demo", bgr_planes[0]);
//计算直方图
int histSize = 256;
float range[] = { 0,256 };
const float *histRanges = { range };
Mat b_hist, g_hist, r_hist;
calcHist(&bgr_planes[0], 1, 0, Mat(), b_hist, 1, &histSize, &histRanges, true, false);
calcHist(&bgr_planes[1], 1, 0, Mat(), g_hist, 1, &histSize, &histRanges, true, false);
calcHist(&bgr_planes[2], 1, 0, Mat(), r_hist, 1, &histSize, &histRanges, true, false);
//归一化
int hist_h = 400;
int hist_w = 512;
int bin_w = hist_w / histSize;
Mat histImage(hist_w, hist_h, CV_8UC3, Scalar(0, 0, 0));
normalize(b_hist, b_hist, 0, hist_h, NORM_MINMAX, -1, Mat());
normalize(g_hist, g_hist, 0, hist_h, NORM_MINMAX, -1, Mat());
normalize(r_hist, r_hist, 0, hist_h, NORM_MINMAX, -1, Mat());
//render histogram chart
for (int i = 1; i < histSize; i++)
{
line(histImage, Point((i - 1)*bin_w, hist_h - cvRound(b_hist.at
line(histImage, Point((i - 1)*bin_w, hist_h - cvRound(g_hist.at
line(histImage, Point((i - 1)*bin_w, hist_h - cvRound(r_hist.at
}
imshow(OUTPUT_TITLE, histImage);
waitKey(0);
return 0;
}
P26直方图比较
P27直方图反向投影
# include
# include
# include
using namespace std;
using namespace cv;
Mat src; Mat hsv; Mat hue;
int bins = 12;
void Hist_And_Backprojection(int, void*);
int main(int argc, char** agrv)
{
Mat src;
src = imread("C:/Users/25503/Desktop/777.jpg");
if (!src.data)
{
printf("could not load image...\n");
return -1;
}
const char* window_image = "input image";
namedWindow(window_image, CV_WINDOW_AUTOSIZE);
namedWindow("BackProj", CV_WINDOW_AUTOSIZE);
namedWindow("Histogram", CV_WINDOW_AUTOSIZE);
cvtColor(src, hsv, CV_BGR2HSV);
hue.create(hsv.size(), hsv.depth());
int nchannels[] = { 0,0 };
mixChannels(&hsv, 1, &hue, 1, nchannels, 1);
createTrackbar("Histogram Bins:", window_image, &bins, 180, Hist_And_Backprojection);//绘制标尺
Hist_And_Backprojection(0, 0);//直方图反向投影
imshow(window_image, src);
waitKey(0);
return 0;
}
void Hist_And_Backprojection(int, void*)
{
float range[] = { 0,180 };
const float *histRanges = { range };
Mat h_hist;
calcHist(&hue, 1, 0, Mat(), h_hist, 1, &bins, &histRanges, true, false);
normalize(h_hist, h_hist, 0, 255, NORM_MINMAX, -1, Mat());
Mat backPrjImage;
calcBackProject(&hue, 1, 0, h_hist, backPrjImage, &histRanges, 1, true);
imshow("BackProj", backPrjImage);
int hist_h = 400;
int hist_w = 400;
Mat histImage(hist_w, hist_h, CV_8UC3, Scalar(0, 0, 0));
int bin_w = (hist_w / bins);
for (int i = 1; i < bins; i++)
{
rectangle(histImage, Point((i - 1)*bin_w, (hist_h - cvRound(h_hist.at
}
imshow("Histogram", histImage);
return;
}
P28模板匹配1//2021/1/8****
# include
# include
#include
using namespace std;
using namespace cv;
Mat src, temp, dst;
int match_method = CV_TM_SQDIFF;
int max_track = 5;
const char* INPUT_T = "input image";
const char* OUTPUT_T = "result image";
const char* match_t = "template match-demo";
void Match_Demo(int, void*);
int main(int argc, char**agrv)
{
src = imread("C:/Users/25503/Desktop/888.png");//原图像
temp = imread("C:/Users/25503/Desktop/999.png");//模板图像(原图像子图像)
if (src.empty() || temp.empty())
{
printf("could not load image...\n");
return -1;
}
namedWindow(INPUT_T, CV_WINDOW_AUTOSIZE);
namedWindow(OUTPUT_T, CV_WINDOW_AUTOSIZE);
namedWindow(match_t, CV_WINDOW_AUTOSIZE);
imshow(INPUT_T, temp);
const char* trackbar_title = "Match Algo Type";
createTrackbar(trackbar_title, OUTPUT_T, &match_method, max_track, Match_Demo);
Match_Demo(0, 0);
waitKey(0);
return 0;
}
void Match_Demo(int, void*)
{
int width = src.cols - temp.cols + 1;
int height = src.rows - temp.rows + 1;
Mat result(width, height, CV_32FC1);
matchTemplate(src, temp, result, match_method, Mat());
normalize(result, result, 0, 1, NORM_MINMAX, -1, Mat());
Point minLoc;
Point maxLoc;
double min, max;
src.copyTo(dst);
Point temLoc;
minMaxLoc(result, &min, &max, &minLoc,&maxLoc, Mat());
if (match_method == CV_TM_SQDIFF || match_method == CV_TM_SQDIFF_NORMED)
{
temLoc = minLoc;
}
else
{
temLoc = maxLoc;
}
//绘制矩形框
rectangle(dst, Rect(temLoc.x, temLoc.y, temp.cols, temp.rows), Scalar(0, 0, 255), 2, 8);
rectangle(result, Rect(temLoc.x, temLoc.y, temp.cols, temp.rows), Scalar(0, 0, 255), 2, 8);
imshow(OUTPUT_T, result);
imshow(match_t, dst);
}
P28模板匹配2//2021/1/8****
#include
#include
#include
#include
#include
using namespace std;
using namespace cv;
/**********************************************************
*
* input:
* argc-----current mass center point
* argv-----previous mass center point
*
**********************************************************/
int main(int argc, char **argv)
{
Mat pFrame;//read frame from video
Mat pFrameGray;
VideoCapture pCapture;
pCapture.open("./plane.mov");
if (!pCapture.isOpened())
{
cout << "open video error" << endl;
return -1;
}
Mat temp;
temp = imread("./plane.png", 0);//read a gray template
if (!temp.data)
{
cout << "read template pic error" << endl;
return -1;
}
namedWindow("template tracking");
moveWindow("template tracking", 100, 100);
Mat result;//save template match result
while (1)
{
pCapture.read(pFrame);//read a frame from video
cvtColor(pFrame, pFrameGray, CV_BGR2GRAY);
matchTemplate(pFrameGray, temp, result, TM_SQDIFF);
//location
double minValue;
double maxValue;
//location point
Point minLocP;
Point maxLocP;
//match locat
minMaxLoc(result, &minValue, &maxValue, &minLocP, &maxLocP, Mat());
rectangle(pFrame, Rect(minLocP.x, minLocP.y, temp.cols, temp.rows), Scalar(0, 0, 255), 2, 8, 0);
imshow("template tracking", pFrame);
waitKey(33);
}
return 0;
}
P29轮廓发现***
# include
# include
# include
using namespace std;
using namespace cv;
Mat src, dst;
const char* output_win = "findcontours-demo";
int threshold_value = 100;
int threshold_max = 255;
RNG rng;
void Demo_Contours(int, void*);
int main(int agrc, char** agrv)
{
src = imread("C:/Users/25503/Desktop/11.png");
if (src.empty())
{
printf("could not load image...\n");
return -1;
}
namedWindow("input-image", CV_WINDOW_AUTOSIZE);
namedWindow(output_win, CV_WINDOW_AUTOSIZE);
imshow("input-image", src);
cvtColor(src, src, CV_BGR2GRAY);
const char* trackbar_title = "Threshold Value";
createTrackbar(trackbar_title, output_win, &threshold_value, threshold_max, Demo_Contours);
Demo_Contours(0, 0);
waitKey(0);
return 0;
}
void Demo_Contours(int, void*)
{
Mat canny_output;
vector
vector
Canny(src, canny_output, threshold_value, threshold_value * 2, 3, false);
findContours(canny_output, contours, hierachy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));//发现轮廓
dst = Mat::zeros(src.size(), CV_8UC3);
RNG rng(12345);
for (size_t i = 0; i < contours.size(); i++)
{
Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));//轮廓颜色
drawContours(dst, contours, i, color, 2, 8, hierachy, 0, Point(0, 0));//绘制轮廓
}
imshow(output_win, dst);
}
P30凸包
P31轮廓周围绘制矩形和圆形框绘制*****
# include
# include
# include
using namespace std;
using namespace cv;
Mat src, gray_src,drawImg;
const char* output_win = "rectangle-demo";
int threshold_v = 170;
int threshold_max = 255;
RNG rng(12345);
void Contours_Callback(int, void*);
int main(int agrc, char** agrv)
{
src = imread("C:/Users/25503/Desktop/11.png");
if (src.empty())
{
printf("could not load image...\n");
return -1;
}
cvtColor(src, gray_src, CV_BGR2GRAY);
blur(gray_src, gray_src, Size(3, 3), Point(-1, -1));
const char* source_win = "input image";
namedWindow(source_win, CV_WINDOW_AUTOSIZE);
namedWindow(output_win, CV_WINDOW_AUTOSIZE);
imshow(source_win, src);
createTrackbar("Threshold Value:", output_win, &threshold_v, threshold_max, Contours_Callback);
Contours_Callback(0, 0);
waitKey(0);
return 0;
}
void Contours_Callback(int, void*)
{
Mat binary_output;
vector
vector
threshold(gray_src, binary_output, threshold_v, threshold_max, THRESH_BINARY);
imshow("binary image", binary_output);
findContours(binary_output, contours, hierachy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(-1, -1));
vector
vector
vector
vector
vector
vector
for (size_t i = 0; i < contours.size(); i++)
{
approxPolyDP(Mat(contours[i]), contours_ploy[i], 3, true);
ploy_rects[i] = boundingRect(contours_ploy[i]);
minEnclosingCircle(contours_ploy[i], ccs[i], radius[i]);
if (contours_ploy[i].size() > 5)
{
myellipse[i] = fitEllipse(contours_ploy[i]);
minRects[i] = minAreaRect(contours_ploy[i]);
}
}
//draw it
src.copyTo(drawImg);
Point2f pts[4];
for (size_t t = 0; t < contours.size(); t++)
{
Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
//rectangle(drawImg, ploy_rects[t], color, 2, 8);
//circle(drawImg, ccs[t], radius[t], color, 2, 8);
if (contours_ploy[t].size() > 5)
{
ellipse(drawImg, myellipse[t], color, 2, 8);
minRects[t].points(pts);
for (int r = 0; r < 4; r++)
{
line(drawImg, pts[r], pts[(r + 1) % 4], color, 2, 8);
}
}
}
imshow("矩形框+圆形框", drawImg);
return;
}
P32图像矩-计算弧长、面积(适用于多个细胞面积计算)*****
# include
# include
# include
using namespace std;
using namespace cv;
Mat src, gray_src;
const char* output_win = "image moents demo";
int threshold_value = 80;
int threshold_max = 255;
RNG rng(12345);
void Dem0_Moment(int, void*);
int main(int agrc, char** agrv)
{
src = imread("C:/Users/25503/Desktop/888.png");
if (src.empty())
{
printf("could not load image...\n");
return -1;
}
cvtColor(src, gray_src, CV_BGR2GRAY);
GaussianBlur(gray_src, gray_src, Size(3, 3), 0,0);
const char* input_win = "input image";
namedWindow(input_win, CV_WINDOW_AUTOSIZE);
namedWindow(output_win, CV_WINDOW_AUTOSIZE);
imshow(input_win, src);
createTrackbar("Threshold Value:", output_win, &threshold_value, threshold_max, Dem0_Moment);
Dem0_Moment(0, 0);
waitKey(0);
return 0;
}
void Dem0_Moment(int, void*)
{
Mat canny_output;
vector
vector
Canny(gray_src, canny_output, threshold_value, threshold_value * 2, 3, false);
findContours(canny_output, contours, hierachy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));
vector
vector
for (size_t i = 0; i < contours.size(); i++)
{
contours_moments[i] = moments(contours[i]);
ccs[i] = Point(static_cast
}
Mat drawImg;
src.copyTo(drawImg);
for (size_t i = 0; i < contours.size(); i++)
{
if (contours[i].size() < 30)//直径小于30的不显示,数字30可以修改
{
continue;
}
Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
printf("center point x: %.2f y: %.2f\n", ccs[i].x, ccs[i].y);
printf("contours %d area :%.2f arc length :%.2f\n", i, contourArea(contours[i]), arcLength(contours[i], true));
drawContours(drawImg, contours, i, color, 2, 8, hierachy, 0, Point(0, 0));
circle(drawImg, ccs[i], 2, color, 2, 8);
}
imshow(output_win, drawImg);
return;
}
P33点多边形测试-测试一个点或者多个点是否在多边形内部、边缘或者外部
# include
# include
#include
using namespace std;
using namespace cv;
int main(int agrc, char** agrv)
{
const int r = 100;
Mat src = Mat::zeros(r * 4, r * 4, CV_8UC1);
vector
vert[0] = Point(3 * r / 2, static_cast
vert[1] = Point(1 *r, 2 * r);
vert[2] = Point(3 * r / 2, static_cast
vert[3] = Point(5 * r / 2, static_cast
vert[4] = Point(3 * r ,2 *r);
vert[5] = Point(5 * r / 2, static_cast
for (int i = 0; i < 6; i++)
{
line(src, vert[i], vert[(i + 1) % 6], Scalar(255), 3, 8, 0);
}
vector
vector
Mat csrc;
src.copyTo(csrc);
findContours(csrc, contours, hierachy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));
Mat raw_dist = Mat::zeros(csrc.size(), CV_32FC1);
for (int row = 0; row < raw_dist.rows; row++)
{
for (int col = 0; col < raw_dist.cols; col++)
{
double dist = pointPolygonTest(contours[0], Point2f(static_cast
raw_dist.at
}
}
double minValue, maxValue;
minMaxLoc(raw_dist, &minValue, &maxValue, 0, 0, Mat());
Mat drawImg = Mat::zeros(src.size(), CV_8UC3);
for (int row = 0; row < drawImg.rows; row++)
{
for (int col = 0; col < drawImg.cols; col++)
{
float dist = raw_dist.at
if (dist > 0)
{
drawImg.at
}
else if (dist < 0)
{
drawImg.at
}
else
{
drawImg.at
drawImg.at
drawImg.at
}
}
}
const char* output_win = "point polygon test demo";
char input_win[] = "input image";
namedWindow(input_win, CV_WINDOW_AUTOSIZE);
namedWindow(output_win, CV_WINDOW_AUTOSIZE);
imshow(input_win, src);
imshow(output_win, drawImg);
waitKey(0);
return 0;
}
P34-P35基于距离变换与分水岭的图像分割*****
//基于距离变换和分水岭的图像分割(image segmentation)
//图像分割的目标是将图像中像素根据一定的规则分为若干(N)个cluster集合,每个集合包含一类像素。
//步骤:1.将白色背景变成黑色-目的是为后面的变换做准备
//2. 使用filter2D与拉普拉斯算子实现图像对比度提高,sharp
//3. 转为二值图像通过threshold
//4. 距离变换
//5. 对距离变换结果进行归一化到[0~1]之间
//6. 使用阈值,再次二值化,得到标记
//7. 腐蚀得到每个Peak - erode
//8.发现轮廓 – findContours
//9. 绘制轮廓 - drawContours
//10.分水岭变换 watershed
//11. 对每个分割区域着色输出结果
#include
#include
#include
using namespace std;
using namespace cv;
int main(int argc, char*argv)
{
Mat src;
src = imread("C:/Users/25503/Desktop/888.png");
if (!src.data)
{
printf("could not load image...\n");
return -1;
}
namedWindow("input", CV_WINDOW_AUTOSIZE);
imshow("input", src);
//将白色背景变成黑色-目的是为后面的变换做准备
for (int row = 0; row < src.rows; row++)
{
for (int col = 0; col < src.cols; col++)
{
if (src.at
{
src.at
src.at
src.at
}
}
}
const char*input = "change backgroud image";
namedWindow(input, CV_WINDOW_AUTOSIZE);
imshow(input, src);
//使用filter2D与拉普拉斯算子实现图像对比度提高,sharp
Mat imgLaplance;
Mat sharp = src;
Mat kernel = (Mat_
filter2D(sharp, imgLaplance, CV_32F, kernel, Point(-1, -1), 0, BORDER_DEFAULT);
src.convertTo(sharp, CV_32F);
Mat imgResult = sharp - imgLaplance;
//显示
imgResult.convertTo(imgResult, CV_8UC3);
imgLaplance.convertTo(imgLaplance, CV_8UC3);
namedWindow("Sharp image", CV_WINDOW_AUTOSIZE);
imshow("Sharp image", imgResult);
// src = resultImg; // copy back
//binary image转为二值图像通过threshold
Mat binaryImag;
cvtColor(src, binaryImag, CV_BGR2GRAY);
threshold(binaryImag, binaryImag, 40, 255, THRESH_OTSU | THRESH_BINARY);
namedWindow("binary image", CV_WINDOW_AUTOSIZE);
imshow("binary image", binaryImag);
//距离变换(distance transform )
Mat distImg;
distanceTransform(binaryImag, distImg, DIST_L1, 3, 5);
//cv::distanceTransform(InputArray src, OutputArray dst, OutputArray labels, int distanceType, int maskSize, int labelType=DIST_LABEL_CCOMP)
//distanceType = DIST_L1 / DIST_L2,
//maskSize = 3x3, 最新的支持5x5,推荐3x3、
//labels离散维诺图输出
//dst输出8位或者32位的浮点数,单一通道,大小与输入图像一致
//对距离变换结果进行归一化到[0~1]之间
normalize(distImg, distImg, 0, 1, NORM_MINMAX);
imshow("distance image", distImg);
//使用阈值,再次二值化,得到标记(binary again)
threshold(distImg, distImg, .2, 1, THRESH_BINARY);
//腐蚀得到每个Peak - erode
Mat kernel1 = Mat::ones(13, 13, CV_8UC1);
erode(distImg, distImg, kernel1, Point(-1, -1));
imshow("distance binary image", distImg);
// markers (发现轮廓 – findContours)
Mat dist_8u;
distImg.convertTo(dist_8u, CV_8U);
vector
findContours(dist_8u, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE, Point(0, 0));
// create makers(绘制轮廓 - drawContours)
Mat markers = Mat::zeros(src.size(), CV_32SC1);
for (size_t i = 0; i < contours.size(); i++) {
drawContours(markers, contours, static_cast
}
circle(markers, Point(5, 5), 3, Scalar(255, 255, 255), -1);
imshow("my markers", markers * 1000);
// perform watershed(基于浸泡理论实现 )
watershed(src, markers);
Mat mark = Mat::zeros(markers.size(), CV_8UC1);
markers.convertTo(mark, CV_8UC1);
//src.convertTo(dst, type, scale, shift)
//dst:目的矩阵;
//type:需要的输出矩阵类型,或者更明确的,是输出矩阵的深度,如果是负值(常用 - 1)则输出矩阵和输入矩阵类型相同;
//scale : 比例因子;
//shift:将输入数组元素按比例缩放后添加的值;
bitwise_not(mark, mark, Mat());
imshow("watershed image", mark);
// generate random color
vector
for (size_t i = 0; i < contours.size(); i++) {
int r = theRNG().uniform(0, 255);
int g = theRNG().uniform(0, 255);
int b = theRNG().uniform(0, 255);
colors.push_back(Vec3b((uchar)b, (uchar)g, (uchar)r));
}
// fill with color and display final result(对每个分割区域着色输出结果)
Mat dst = Mat::zeros(markers.size(), CV_8UC3);
for (int row = 0; row < markers.rows; row++) {
for (int col = 0; col < markers.cols; col++) {
int index = markers.at
if (index > 0 && index <= static_cast
dst.at
}
else {
dst.at
}
}
}
imshow("Final Result", dst);
waitKey(0);
return 0;
}
P36-P37特征提取与检测实战概述2021/1/9
P38 -P39 Harris角点检测
#include
#include
#include
using namespace cv;
using namespace std;
void Harris_demo(int, void*);
int thres_value = 130;
int thres_Max = 255;
Mat src, gray_src;
const char* outputTitle = "output title";
int main(int argc, char** argv)
{
src = imread("C:/Users/25503/Desktop/888.png");
if (src.empty())
{
cout << "图片为空" << endl;
return -1;
}
cvtColor(src, gray_src, CV_BGR2GRAY);
namedWindow(outputTitle, CV_WINDOW_AUTOSIZE);
createTrackbar("Harris", outputTitle, &thres_value, thres_Max, Harris_demo);
Harris_demo(0, 0);
imshow("input title", src);
waitKey(0);
return 0;
}
void Harris_demo(int, void *)
{
Mat dst, norm_dst;
dst = Mat::zeros(gray_src.size(), CV_32FC1);
cornerHarris(gray_src, dst, 2, 3, 0.04, BORDER_DEFAULT);
normalize(dst, norm_dst, 0, 255, NORM_MINMAX, CV_32FC1, Mat());
convertScaleAbs(norm_dst, norm_dst);
Mat resultImg = src.clone();
for (int row = 0; row < resultImg.rows; row++)
{
uchar* currentRow = norm_dst.ptr(row);
for (int col = 0; col < resultImg.cols; col++)
{
int value = (int)*currentRow;
if (value > thres_value)
{
circle(resultImg, Point(col, row), 2, Scalar(0, 0, 255), 2, 8, 0);
}
currentRow++;
}
}
imshow(outputTitle, resultImg);
}
P40 Shi-Tomasi角点检测
# include
# include
using namespace cv;
using namespace std;
int num_corners = 25;
int max_corners = 500;
const char* output_title = "ShiTomasi Detector";
void ShiTomasi_Demo(int, void*);
Mat src, gray_src;
RNG rng(12345);
int main(int argc, char* agrv)
{
src = imread("C:/Users/25503/Desktop/110.png");
if (src.empty())
{
printf("could not load image...\n");
return -1;
}
namedWindow("input image", CV_WINDOW_AUTOSIZE);
imshow("input image", src);
cvtColor(src, gray_src, COLOR_BGR2GRAY);
namedWindow(output_title, CV_WINDOW_AUTOSIZE);
createTrackbar("Num Corners", output_title, &num_corners, max_corners, ShiTomasi_Demo);
ShiTomasi_Demo(0, 0);
waitKey(0);
return 0;
}
void ShiTomasi_Demo(int, void*)
{
if (num_corners < 5)
{
num_corners = 5;
}
vector
double qualityLevel = 0.01;
double minDistance = 10;
int blockSize = 3;
bool useHarris = false;
double k = 0.04;
Mat resultImg = gray_src.clone();
cvtColor(resultImg, resultImg, COLOR_GRAY2BGR);
goodFeaturesToTrack(gray_src, corners, num_corners, qualityLevel, minDistance, Mat(), blockSize, useHarris, k);
printf("number of Detected Corners:%d\n", corners.size());
for (size_t t = 0; t < corners.size(); t++)
{
circle(resultImg, corners[t], 2, Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255)), 2, 8, 0);
}
imshow(output_title, resultImg);
}
P41-P42自定义角点检测器
#include
#include
#include
using namespace cv;
using namespace std;
Mat src, gray_src;
int current_value = 30;
int Max_value = 100;
double minVal;
double maxVal;
Mat harris_res, harris_src;
void custom_corner_harris(int, void*);
const char* output_title = "output title";
int main(int argc, char** argv)
{
src = imread("C:/Users/25503/Desktop/110.png");
if (src.empty())
{
cout << "the image could not found..." << endl;
return -1;
}
cvtColor(src, gray_src, COLOR_BGR2GRAY);
harris_src = Mat::zeros(src.size(), CV_32FC(6));
harris_res = Mat::zeros(src.size(), CV_32FC1);
imshow("input title", src);
// 计算特征值
int blocksize = 3;
double k = 0.04;
int ksize = 3; //Sobel算子当中的核大小,只能取1、3、5、7
cornerEigenValsAndVecs(gray_src, harris_src, blocksize, ksize, BORDER_DEFAULT);
//计算响应
for (int row = 0; row < harris_src.rows; row++)
{
for (int col = 0; col < harris_src.cols; col++)
{
double lamda1 = harris_src.at
double lamda2 = harris_src.at
harris_res.at
}
}
minMaxLoc(harris_res, &minVal, &maxVal, 0, 0, Mat());
namedWindow(output_title, CV_WINDOW_AUTOSIZE);
createTrackbar("custom bar", output_title, ¤t_value, Max_value, custom_corner_harris);
custom_corner_harris(0, 0);
waitKey(0);
return 0;
}
void custom_corner_harris(int, void*)
{
if (current_value < 10)
{
current_value = 10;
}
//cvtColor(gray_src, gray_src, COLOR_GRAY2BGR);
Mat resultImg = gray_src.clone();
cvtColor(resultImg, resultImg, COLOR_GRAY2BGR);
RNG rng(12345);
Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
float t = static_cast
for (int row = 0; row < src.rows; row++)
{
for (int col = 0; col < src.cols; col++)
{
float v = harris_res.at
if (v > t)
{
circle(resultImg, Point(col, row), 2, Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255)), 2, 8, 0);
}
}
}
printf("corner num:%d\n", current_value);
imshow(output_title, resultImg);
}
P43 亚像素级别角点检测-目的是提高检测的准确性(可以具体到小数点后三位)项目常用于提高精度*******
#include
#include
#include
using namespace std;
using namespace cv;
Mat src, gray_src;
int maxCorner = 20;
int max_value = 200;
const char* output_title = "subpixel window";
void subpixel(int, void*);
int main(int argc, char** argv)
{
src = imread("C:/Users/25503/Desktop/110.png");
if (!src.data)
{
cout << "图片未找到" << endl;
return -1;
}
cvtColor(src, gray_src, CV_BGR2GRAY);
imshow("input title", src);
namedWindow(output_title, CV_WINDOW_AUTOSIZE);
createTrackbar("subpixel num", output_title, &maxCorner, max_value, subpixel);
subpixel(0, 0);
waitKey(0);
return 0;
}
void subpixel(int, void *)
{
if (maxCorner < 5)
{
maxCorner = 5;
}
vector
goodFeaturesToTrack(gray_src, corners, maxCorner, 0.01, 10, Mat(), 3, false, 0.04);
Mat resultImg = src.clone();
for (size_t i = 0; i < corners.size(); i++)
{
circle(resultImg, corners[i], 2, Scalar(0, 0, 255), 2, 8, 0);
}
cout << "corner num: " << corners.size() << endl;
imshow(output_title, resultImg);
Size size = Size(5, 5);//最多只能取到5
//迭代算法的终止准则,该类变量需要3个参数,一个是类型,第二个参数为迭代的最大次数,最后一个是特定的阈值
TermCriteria tc = TermCriteria(TermCriteria::EPS + TermCriteria::MAX_ITER, 40, 0.01);
cornerSubPix(gray_src, corners, size, Size(-1, -1), tc);
//这里的corner重新变了,变成cornerSubPix里的corners了
for (size_t t = 0; t < corners.size(); t++)
{
cout << t + 1 << ".pixel[x,y]= " << corners[t].x << "," << corners[t].y << endl;
}
return;
}
P44 -P45 SURF特征检测--失败
#include
#include
#include
#include
using namespace cv;
using namespace cv::xfeatures2d;
using namespace std;
Mat g_srcImage, g_grayImage, g_keyPointImage;
int main()
{
g_srcImage = cv::imread("curry_dlt.jpg", 0);
if (g_srcImage.empty())
{
printf("read image fail\n");
return -1;
}
imshow("g_srcImage", g_srcImage);
int minHessian = 400;
// SURF特征检测
vector
Ptr
detector->detect(g_srcImage, keyPoints, Mat());
// 绘制关键点
g_keyPointImage = g_srcImage.clone();
drawKeypoints(g_srcImage, keyPoints, g_keyPointImage, Scalar::all(-1), DrawMatchesFlags::DEFAULT);
imshow("g_keyPointImage", g_keyPointImage);
waitKey(0);
return 0;
}
P46-P47 SIFT特征检测--失败
#include
#include
#include
#include
using namespace cv;
using namespace std;
using namespace cv::xfeatures2d;
Mat src;
int main(int argc, char** argv)
{
src = imread("D:/test/src.png",IMREAD_GRAYSCALE);
if (!src.data)
{
cout << "图片未找到" << endl;
return -1;
}
imshow("input title", src);
int numfeature = 400;
Ptr
vector
detector->detect(src, keypoints, Mat());
Mat resultImg;
drawKeypoints(src, keypoints, resultImg, Scalar::all(-1), DrawMatchesFlags::DEFAULT);
imshow("SIFT keypoint", resultImg);
waitKey(0);
return 0;
}
P48-P49 HOG特征检测--框选择
#include
#include
using namespace cv;
using namespace std;
int main(int agrc, char** agrv)
{
Mat src = imread("C:/Users/25503/Desktop/1122.png");
if (src.empty())
{
namedWindow("input image", CV_WINDOW_AUTOSIZE);
imshow("input image", src);
}
Mat dst, dst_gray;
resize(src, dst, Size(64, 128));
cvtColor(dst, dst_gray, COLOR_BGR2GRAY);
//HOGDescriptor detector(Size(64, 128), Size(16, 16), Size(8, 8), Size(8, 8), 9);
//vector
//vector
//printf("number of HOG descriptors:%d", descriptors.size());
HOGDescriptor hog = HOGDescriptor();
hog.setSVMDetector(hog.getDefaultPeopleDetector());
vector
hog.detectMultiScale(src, foundLocations, 0, Size(8, 8), Size(32, 32), 1.05, 2);
Mat result = src.clone();
for (rsize_t t = 0; t < foundLocations.size(); t++)
{
rectangle(result, foundLocations[t], Scalar(0, 0, 255), 2, 8, 0);
}
namedWindow("HOG SVM Detector Demo", CV_WINDOW_AUTOSIZE);
imshow("HOG SVM Detector Demo",result);
}
P50-P52LBP特征检测
#include
#include
#include
using namespace cv;
using namespace std;
int main(int agrc, char** agrv)
{
Mat src, dst;
Mat gray_src;
src = imread("C:/Users/25503/Desktop/1122.png");
if (src.empty())
{
namedWindow("input image", CV_WINDOW_AUTOSIZE);
imshow("input image", src);
}
const char* output_tt = "LBP Result";
namedWindow("input image", CV_WINDOW_AUTOSIZE);
namedWindow(output_tt, CV_WINDOW_AUTOSIZE);
imshow("input image", src);
//convert to gray
cvtColor(src, gray_src, COLOR_BGR2GRAY);
int width = gray_src.cols;
int height = gray_src.rows;
Mat ibpImage = Mat::zeros(gray_src.rows - 2, gray_src.cols - 2, CV_8UC1);
for (int row = 1; row < height - 1; row++)
{
for (int col = 1; col < width - 1; col++)
{
uchar c = gray_src.at
uchar code = 0;
code |= (gray_src.at
code |= (gray_src.at
code |= (gray_src.at
code |= (gray_src.at
code |= (gray_src.at
code |= (gray_src.at
code |= (gray_src.at
code |= (gray_src.at
ibpImage.at
}
}
imshow(output_tt, ibpImage);
waitKey(0);
return 0;
}
P53 积分图计算
# include
# include
using namespace cv;
int main(int agrc, char** agrv)
{
Mat src = imread("C:/Users/25503/Desktop/1122.png");
if (src.empty())
{
printf("could not load image...\n");
return -1;
}
namedWindow("input image", CV_WINDOW_AUTOSIZE);
imshow("input image", src);
Mat sumii = Mat::zeros(src.rows + 1, src.cols + 1, CV_32FC1);
Mat sqsumii = Mat::zeros(src.rows + 1, src.cols + 1, CV_64FC1);
integral(src, sumii, sqsumii);
Mat iiResult;
normalize(sumii, iiResult, 0, 255, NORM_MINMAX, CV_8UC1, Mat());
imshow("Integral Image", iiResult);
waitKey(0);
return 0;
}
P54 Harris特征检测-基于积分图(后续有相关代码)
P55特征描述子2021/1/12--模板匹配
# include
# include
# include
using namespace cv;
using namespace std;
using namespace cv::xfeatures2d;
int main(int agrc, char** agrv)
{
Mat img1 = imread("C:/Users/25503/Desktop/1122.png",IMREAD_GRAYSCALE);
Mat img2 = imread("C:/Users/25503/Desktop/110.png", IMREAD_GRAYSCALE);
if (!img1.data || !img2.data)
{
return -1;
}
imshow("image1", img1);
imshow("image2", img2);
int minHessian = 400;
Ptr
vector
vector
Mat descriptor_1, descriptor_2;
detector->detectAndCompute(img1, Mat(), keypoints_1, descriptor_1);
detector->detectAndCompute(img2, Mat(), keypoints_2, descriptor_2);
BFMatcher matcher;
vector
matcher.match(descriptor_1, descriptor_2, matches);
Mat matchesImg;
drawMatches(img1, keypoints_1, img2, keypoints_2, matches, matchesImg);
imshow("Descriptor Demo", matchesImg);
waitKey(0);
return 0;
}
P56 FLANN特征匹配(原图像和子图像)失败
#include
#include
#include
#include
using namespace cv;
using namespace std;
using namespace cv::xfeatures2d;
//检测计算和绘制时,源图(img1)在前面,目标图像(img2)在后面
Mat img1, img2;
int main(int argc, char**argv)
{
img1 = imread("C:/Users/25503/Desktop/888.png", 0);
img2 = imread("C:/Users/25503/Desktop/999.png", 0);
if (!img1.data || !img2.data)
{
cout << "图片为空!" << endl;
return -1;
}
int minHesssion = 400;
Ptr
vector
vector
Mat descript_obj, descript_scene;
detector->detectAndCompute(img1, Mat(), keypoints_obj, descript_obj); //检测并计算特征描述子
detector->detectAndCompute(img2, Mat(), keypoints_scene, descript_scene);
FlannBasedMatcher fbmatcher;
vector
fbmatcher.match(descript_obj, descript_scene, matches); //特征描述子匹配
//找出最优特征点
double minDist = 1000; //初始化最大最小距离
double maxDist = 0;
for (int i = 0; i < descript_obj.rows; i++)
{
double dist = matches[i].distance;
if (dist > maxDist)
{
maxDist = dist;
}
if (dist < minDist)
{
minDist = dist;
}
}
printf("maxDist:%f\n", maxDist);
printf("minDist:%f\n", minDist);
vector
for (int i = 0; i < descript_obj.rows; i++)
{
double dist = matches[i].distance;
if (dist < max(2 * minDist, 0.02)) {
goodMatches.push_back(matches[i]);
}
}
Mat resultImg;
drawMatches(img1, keypoints_obj, img2, keypoints_scene, goodMatches, resultImg, Scalar::all(-1),
Scalar::all(-1), vector
);
imshow("input image1", img1);
imshow("input image2", img2);
imshow("FlannBasedMatcher demo", resultImg);
waitKey(0);
return 0;
}
P57 平面对象识别--失败
#include
#include
using namespace cv;
using namespace cv::xfeatures2d;
int main()
{
Mat src1, src2;
src1 = imread("E:/image/image/card.jpg");
src2 = imread("E:/image/image/cards.jpg");
if (src1.empty() || src2.empty())
{
printf("can ont load images....\n");
return -1;
}
imshow("image1", src1);
imshow("image2", src2);
int minHessian = 400;
//选择SURF特征
Ptr
std::vector
std::vector
Mat descriptor1, descriptor2;
//检测关键点并计算描述符
detector->detectAndCompute(src1, Mat(), keypoints1, descriptor1);
detector->detectAndCompute(src2, Mat(), keypoints2, descriptor2);
//基于Flann的描述符匹配器
FlannBasedMatcher matcher;
std::vector
//从查询集中查找每个描述符的最佳匹配
matcher.match(descriptor1, descriptor2, matches);
double minDist = 1000;
double maxDist = 0;
for (int i = 0; i < descriptor1.rows; i++)
{
double dist = matches[i].distance;
printf("%f \n", dist);
if (dist > maxDist)
{
maxDist = dist;
}
if (dist < minDist)
{
minDist = dist;
}
}
//DMatch类用于匹配关键点描述符的
std::vector
for (int i = 0; i < descriptor1.rows; i++)
{
double dist = matches[i].distance;
if (dist < max(2 * minDist, 0.02))
{
goodMatches.push_back(matches[i]);
}
}
Mat matchesImg;
drawMatches(src1, keypoints1, src2, keypoints2, goodMatches, matchesImg, Scalar::all(-1),
Scalar::all(-1), std::vector
std::vector
for (int i = 0; i < goodMatches.size(); i++)
{
point1.push_back(keypoints1[goodMatches[i].queryIdx].pt);
point2.push_back(keypoints2[goodMatches[i].trainIdx].pt);
}
Mat H = findHomography(point1, point2, RANSAC);
std::vector
std::vector
cornerPoints1[0] = Point(0, 0);
cornerPoints1[1] = Point(src1.cols, 0);
cornerPoints1[2] = Point(src1.cols, src1.rows);
cornerPoints1[3] = Point(0, src1.rows);
perspectiveTransform(cornerPoints1, cornerPoints2, H);
//绘制出变换后的目标轮廓,由于左侧为图像src2故坐标点整体右移src1.cols
line(matchesImg, cornerPoints2[0] + Point2f(src1.cols, 0), cornerPoints2[1] + Point2f(src1.cols, 0), Scalar(0, 255, 255), 4, 8, 0);
line(matchesImg, cornerPoints2[1] + Point2f(src1.cols, 0), cornerPoints2[2] + Point2f(src1.cols, 0), Scalar(0, 255, 255), 4, 8, 0);
line(matchesImg, cornerPoints2[2] + Point2f(src1.cols, 0), cornerPoints2[3] + Point2f(src1.cols, 0), Scalar(0, 255, 255), 4, 8, 0);
line(matchesImg, cornerPoints2[3] + Point2f(src1.cols, 0), cornerPoints2[0] + Point2f(src1.cols, 0), Scalar(0, 255, 255), 4, 8, 0);
//在原图上绘制出变换后的目标轮廓
line(src2, cornerPoints2[0], cornerPoints2[1], Scalar(0, 255, 255), 4, 8, 0);
line(src2, cornerPoints2[1], cornerPoints2[2], Scalar(0, 255, 255), 4, 8, 0);
line(src2, cornerPoints2[2], cornerPoints2[3], Scalar(0, 255, 255), 4, 8, 0);
line(src2, cornerPoints2[3], cornerPoints2[0], Scalar(0, 255, 255), 4, 8, 0);
imshow("output", matchesImg);
imshow("output2", src2);
waitKey();
return 0;
}
P58-P59 AKAZE局部匹配*******成功
#include
#include
#include
using namespace cv;
using namespace std;
Mat img1, img2;
int main(int argc, char** argv)
{
img1 = imread("C:/Users/25503/Desktop/888.png", IMREAD_GRAYSCALE);
img2 = imread("C:/Users/25503/Desktop/999.png", IMREAD_GRAYSCALE);
if (!img1.data || !img2.data)
{
printf("图片未找到...");
return -1;
}
imshow("input box", img1);
imshow("input box_in_scene", img2);
double t1 = getTickCount();
//检测特征点(非线性)
Ptr
//Ptr
//存放描述子
Mat descriptor_obj, descriptor_scene;
//img1特征点检测并计算描述子
vector
detector->detectAndCompute(img1, Mat(), keypoints_obj, descriptor_obj);
//img2特征点检测并计算描述子
vector
detector->detectAndCompute(img2, Mat(), keypoints_scene, descriptor_scene);
double t2 = getTickCount();
double t = (t2 - t1) * 1000 / getTickFrequency();//结果转化为毫秒
printf("特征点寻找所花费时间(ms):%f", t);
//使用FLANN匹配器比较两个关键点的匹配度
FlannBasedMatcher fbMatcher(new flann::LshIndexParams(20, 10, 2));//用LshIndexParams
/*这里不能使用FlannBasedMatcher fbMatcher();这条语句,因为它不支持CV_8UC1类型,
会报错,OpenCv暂时还没有解决这一问题。*/
//也可以使用暴力匹配(BFMatcher bfmatches;)
BFMatcher bfmatches;
vector
fbMatcher.match(descriptor_obj, descriptor_scene, matches);
//绘制匹配线
Mat resultImg;
drawMatches(img1, keypoints_obj, img2, keypoints_scene, matches, resultImg,
Scalar::all(-1), Scalar::all(-1), vector
/*最后一个参数使用DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS就可以把检测到的特征点隐去,
只留下匹配到的特征点。*/
imshow("AKAZE Matches", resultImg);
/*那么上面的操作所显示的结果匹配到的特征点很多,为了减少多余的特征点,下面进行
如下操作*/
vector
/*
1、遍历整个描述子;
2、从描述子中找出最优匹配点(距离最小)
*/
double minDist = 1000;//初始化
double maxDist = 0;
for (int i = 0; i < descriptor_obj.rows; i++)
{
double dist = matches[i].distance;
if (dist > maxDist)
{
maxDist = dist;
}
if (dist < minDist)
{
minDist = dist;
}
}
for (int i = 0; i < descriptor_obj.rows; i++)
{
double dist = matches[i].distance;
if (dist < max(2 * minDist, 0.02))
{
goodmatches.push_back(matches[i]);
}
}
Mat goodmatchesImg;
drawMatches(img1, keypoints_obj, img2, keypoints_scene, goodmatches, goodmatchesImg,
Scalar::all(-1), Scalar::all(-1), vector
imshow("goodmatchesImg", goodmatchesImg);
//用线匹配不直观,用透视矩阵来做
//-------------------平面对象识别(将匹配到的内容替换为矩形)--------------------------
//生成透视变换矩阵
vector
vector
for (size_t i = 0; i < goodmatches.size(); i++)
{
obj.push_back(keypoints_obj[goodmatches[i].queryIdx].pt);
objinscene.push_back(keypoints_scene[goodmatches[i].trainIdx].pt);
}
Mat H = findHomography(obj, objinscene, RANSAC); //生成透视变换矩阵
vector
vector
obj_corner[0] = Point(0, 0);
obj_corner[1] = Point(img1.cols, 0);
obj_corner[2] = Point(img1.cols, img1.rows);
obj_corner[3] = Point(0, img1.rows);
//------------------透视变换---------------------
perspectiveTransform(obj_corner, objinscene_corner, H);
Mat pptfImg = goodmatchesImg.clone();
line(pptfImg, objinscene_corner[0] + Point2f(img1.cols, 0), objinscene_corner[1] + Point2f(img1.cols, 0), Scalar(0, 0, 255), 2, 8, 0);
line(pptfImg, objinscene_corner[1] + Point2f(img1.cols, 0), objinscene_corner[2] + Point2f(img1.cols, 0), Scalar(0, 0, 255), 2, 8, 0);
line(pptfImg, objinscene_corner[2] + Point2f(img1.cols, 0), objinscene_corner[3] + Point2f(img1.cols, 0), Scalar(0, 0, 255), 2, 8, 0);
line(pptfImg, objinscene_corner[3] + Point2f(img1.cols, 0), objinscene_corner[0] + Point2f(img1.cols, 0), Scalar(0, 0, 255), 2, 8, 0);
imshow("pptfImg", pptfImg);
waitKey(0);
return 0;
}
P60 Brisk特征检测与匹配*****成功啦
#include
#include
#include
using namespace cv;
using namespace std;
int main(int argc, char**argv)
{
Mat img1 = imread("C:/Users/25503/Desktop/888.png", IMREAD_GRAYSCALE);
Mat img2 = imread("C:/Users/25503/Desktop/999.png", IMREAD_GRAYSCALE);
if (!img1.data || !img2.data)
{
cout << "图片未找到!!!" << endl;
return -1;
}
imshow("img1_box", img1);
imshow("img2_scene", img2);
//用Brisk算法去检测特征点
vector
vector
double t1 = getTickCount();//计算运行时间
Ptr
Mat desciptor_obj, descriptor_scene;
//检测并计算描述子
detect->detectAndCompute(img1, Mat(), keypoint_obj, desciptor_obj);
detect->detectAndCompute(img2, Mat(), keypoint_scene, descriptor_scene);
double t2 = getTickCount();
double t = (t2 - t1) * 1000 / getTickFrequency();
//匹配描述子,这里使用FLANN匹配,也可以使用(BF)暴力匹配
vector
FlannBasedMatcher fbmatcher(new flann::LshIndexParams(20, 10, 2));
//匹配描述子
fbmatcher.match(desciptor_obj, descriptor_scene, matches);
vector
double minDist = 1000;
double maxDist = 0;//初始化
for (int i = 0; i < desciptor_obj.rows; i++)
{
double dist = matches[i].distance;
if (dist > maxDist)
{
maxDist = dist;
}
if (dist < minDist)
{
minDist = dist;
}
}
for (int i = 0; i < desciptor_obj.rows; i++)
{
double dist = matches[i].distance;
//比最小距离还小的就是最优匹配点
if (dist < max(2 * minDist, 0.02))
{
goodmatches.push_back(matches[i]);
}
}
Mat resultImg;
drawMatches(img1, keypoint_obj, img2, keypoint_scene, goodmatches, resultImg,
Scalar::all(-1), Scalar::all(-1), vector
imshow("BRISK Matches demo", resultImg);
printf("BRISK 执行时间为(ms):%f", t);
//使用透视矩阵画出匹配物体
vector
vector
for (size_t i = 0; i < goodmatches.size(); i++)
{
obj.push_back(keypoint_obj[goodmatches[i].queryIdx].pt);
scene_in_obj.push_back(keypoint_scene[goodmatches[i].trainIdx].pt);
}
//生成透视矩阵
Mat H = findHomography(obj, scene_in_obj, RANSAC);
vector
vector
obj_corner[0] = Point(0, 0);
obj_corner[1] = Point(img1.cols, 0);
obj_corner[2] = Point(img1.cols, img1.rows);
obj_corner[3] = Point(0, img1.rows);
//透视变换
perspectiveTransform(obj_corner, scene_corner, H);
Mat pptfImg = resultImg.clone();
line(pptfImg, scene_corner[0] + Point2f(img1.cols, 0), scene_corner[1] + Point2f(img1.cols, 0), Scalar(0, 0, 255), 2, 8, 0);
line(pptfImg, scene_corner[1] + Point2f(img1.cols, 0), scene_corner[2] + Point2f(img1.cols, 0), Scalar(0, 0, 255), 2, 8, 0);
line(pptfImg, scene_corner[2] + Point2f(img1.cols, 0), scene_corner[3] + Point2f(img1.cols, 0), Scalar(0, 0, 255), 2, 8, 0);
line(pptfImg, scene_corner[3] + Point2f(img1.cols, 0), scene_corner[0] + Point2f(img1.cols, 0), Scalar(0, 0, 255), 2, 8, 0);
imshow("pptfImg demo", pptfImg);
waitKey(0);
return 0;
}
P61 级联分类器--人脸识别**********************成功
#include
#include
#include
using namespace cv;
using namespace std;
int main(int argc, char**argv)
{
String cascadeFilePath = "D:/Opencv3.4.6_build/install/etc/haarcascades/haarcascade_frontalface_alt.xml";//也可以选择其他,例如眼睛等
CascadeClassifier face_casade;
if (!face_casade.load(cascadeFilePath))
{
printf("could not load haar data...\n");
return -1;
}
Mat src, gray_src;
src = imread("C:/Users/25503/Desktop/324.jpg");
cvtColor(src, gray_src, COLOR_BGR2GRAY);
equalizeHist(gray_src, gray_src);
vector
face_casade.detectMultiScale(gray_src, faces, 1.1, 2, 0, Size(120, 120));//size(x,y)的大小可以调节,数值越大,则目标越少
for (size_t t = 0; t < faces.size(); t++)
{
rectangle(src, faces[t], Scalar(0, 0, 255), 3, 8, 0);//绘制矩形框,线宽,线性,线颜色
}
namedWindow("output", CV_WINDOW_AUTOSIZE);
imshow("output", src);
waitKey(0);
return 0;
}
P62概述(无代码)
P63-P65 案例一 切边01 法律文件切边
#include
#include
#include
using namespace cv;
using namespace std;
Mat src, dst, gray_src;
int current_level = 50;
int max_level = 255;
void cut_image(int, void*);
const char* output_title = "rectminArea";
int main(int argc, char**argv)
{
src = imread("C:/Users/25503/Desktop/6667.png", 1);
if (src.empty())
{
cout << "图片未找到" << endl;
return -1;
}
namedWindow(output_title, CV_WINDOW_AUTOSIZE);
createTrackbar("Value", output_title, ¤t_level, max_level, cut_image);
cut_image(0, 0);
imshow("input image", src);
waitKey(0);
return 0;
}
void cut_image(int, void*)
{
Mat canyImg;
cvtColor(src, gray_src, CV_BGR2GRAY);
Canny(gray_src, canyImg, current_level, 2 * current_level, 3, false);
vector
vector
Mat showImg = Mat::zeros(src.size(), CV_8UC3);
findContours(canyImg, contours, hierachy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));
RNG rng(12345);
int minw = src.cols*0.75;
int minh = src.rows*0.75;
Rect box; //获取roi区域
Mat contoursimg = Mat::zeros(src.size(), CV_8UC3);
for (size_t t = 0; t < contours.size(); t++)
{
Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
drawContours(contoursimg, contours, int(t), color, 1, 8, hierachy, 0, Point(0, 0));
RotatedRect minrect = minAreaRect(contours[t]); //获取轮廓的最小外接矩形
float angle = abs(minrect.angle);
if (minrect.size.height > minh && minrect.size.width > minw && minrect.size.width < (src.cols - 5))
{
Point2f pts[4];
minrect.points(pts); //获取最小外接矩形的四个顶点坐标
for (int i = 0; i < 4; i++)
{
line(showImg, pts[i], pts[(i + 1) % 4], color, 2, 8, 0);
cout << "X坐标:" << minrect.center.x << " " << "Y坐标:" << minrect.center.y << " " << "偏移角度:" << angle << endl;
}
box = minrect.boundingRect();
}
if (box.width > 0 && box.height > 0)
{
Mat roiImg = src(box);//截取roi区域
imshow("roiImg", roiImg);
}
}
imshow(output_title, showImg);
imshow("contours image", contoursimg);
}
P66 -P67 案例二 直线检测
#include
#include
#include
using namespace cv;
using namespace std;
void houghlinedetect(int, void*); //定义霍夫检测直线的方法
void morphlogy_houghline(int, void*);//定义形态学+霍夫直线变换的方法
Mat src, roiImg, dst, gray_dst;
int threshold_value = 50;
int max_value = 255;
const char* output_title = "detect lines";
int main(int argc, char** argv)
{
src = imread("C:/Users/25503/Desktop/668.png", 1);
if (src.empty())
{
cout << "图片未找到!" << endl;
return -1;
}
imshow("input image", src);
Rect roi = Rect(8, 8, src.cols - 10, src.rows - 10); //从左上角(8,8),选取这块ROI区域
roiImg = src(roi);
namedWindow(output_title, CV_WINDOW_AUTOSIZE);
//createTrackbar("threshold", output_title, &threshold_value, max_value, houghlinedetect);
//houghlinedetect(0, 0);
morphlogy_houghline(0, 0);
imshow("roiImg", roiImg);
waitKey(0);
return 0;
}
void houghlinedetect(int, void *)
{
//使用边缘检测将图片二值化
Canny(roiImg, dst, threshold_value, 2 * threshold_value, 3, false);
//bitwise_not(dst, dst, Mat());
vector
HoughLinesP(dst, lines, 1, CV_PI / 180.0, 30, 30, 0); //源图需要是二值图像,HoughLines也是一样
cvtColor(dst, gray_dst, COLOR_GRAY2BGR); //GRAY2BGR也是转化为灰度图像的,霍夫变换-直线检测需要使用这个,BGR2GRAY会报错。
for (size_t i = 0; i < lines.size(); i++)
{
Vec4i l = lines[i];
line(gray_dst, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(186, 88, 255), 1, LINE_AA);
}
imshow(output_title, gray_dst);
}
void morphlogy_houghline(int, void*)
{
//二值化操作
Mat binaryImage, morhpImage, resultImg, dilateImg;
cvtColor(roiImg, roiImg, CV_BGR2GRAY);
threshold(roiImg, binaryImage, 0, 255, THRESH_BINARY | THRESH_OTSU);//THRESH_BINARY|THRESH_OTSU 自动确定阈值
bitwise_not(binaryImage, binaryImage, Mat());//当然在threshold中可以使用THRESH_BINARY | THRESH_OTSU直接变成黑色背景
imshow("binary", binaryImage);
//形态学操作,去除除了横线以外的所有字
Mat kernel = getStructuringElement(MORPH_RECT, Size(20, 1), Point(-1, -1));//结构元素,这里使用矩形结构元素,Size(30,1)保留横线,point(-1,-1)表示中心
morphologyEx(binaryImage, morhpImage, MORPH_OPEN, kernel, Point(-1, -1));
imshow("morphologyEx result", morhpImage);
//使用膨胀操作把直线变得更明显点
kernel = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));
dilate(morhpImage, dilateImg, kernel, Point(-1, -1));
imshow("dilateimg result", dilateImg);
//霍夫直线检测
vector
resultImg = roiImg.clone();
HoughLinesP(dilateImg, lines, 1, CV_PI / 180.0, 20, 5, 0);
cvtColor(resultImg, resultImg, CV_GRAY2RGB);
for (size_t i = 0; i < lines.size(); i++)
{
Vec4i L = lines[i];
line(resultImg, Point(L[0], L[1]), Point(L[2], L[3]), Scalar(0, 0, 255), 2, 8, 0);
}
imshow("final result", resultImg);
}
P68-P69 对象提取--在混有噪声的地图轮廓上,将地图轮廓提取出来,并计算轮廓周长与面积
#include
#include
#include
using namespace cv;
using namespace std;
Mat src;
int main(int argc, char** argv)
{
src = imread("C:/Users/25503/Desktop/6689.jpg");
if (src.empty())
{
printf("图片未找到!!!");
return -1;
}
imshow("inut image", src);
//高斯模糊
Mat GaussImg;
GaussianBlur(src, GaussImg, Size(7, 7), 0, 0);
imshow("Gauss Image", GaussImg);
cvtColor(GaussImg, GaussImg, CV_BGR2GRAY);
//二值化操作
Mat binary;
threshold(GaussImg, binary, 0, 255, THRESH_BINARY | THRESH_TRIANGLE);
imshow("binary Image", binary);
//形态学操作
Mat morphImg;
Mat kernel = getStructuringElement(MORPH_RECT, Size(5, 5), Point(-1, -1));
morphologyEx(binary, morphImg, MORPH_CLOSE, kernel, Point(-1, -1), 1);
imshow("morph Image", morphImg);
//轮廓发现
Mat contoursImg = Mat::zeros(src.size(), CV_8UC3);
vector
vector
findContours(morphImg, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE, Point(-1, -1));
for (size_t i = 0; i < contours.size(); i++)
{
Rect rect = boundingRect(contours[i]);
if (rect.width < src.cols / 2)
continue;
drawContours(contoursImg, contours, static_cast
Scalar(0, 0, 255), 2, 8, hireachy, 0, Point(0, 0));
//计算面积与周长
float area = contourArea(contours[i]);
float length = arcLength(contours[i], true);
printf("对象图像面积为:%f\n", area);
printf("对象图像周长为:%f\n", length);
}
imshow("contours Image", contoursImg);
waitKey(0);
return 0;
}
P70-P71 图像计数-----计算玉米粒个数
#include
#include
#include
using namespace cv;
using namespace std;
int main(int argc, char** argv)
{
Mat src = imread("C:/Users/25503/Desktop/1010.jpg");
//medianBlur(src, src,5);//中值滤波,去除椒盐噪声
imshow("src", src);
Mat src_gray, binary;
cvtColor(src, src_gray, COLOR_BGR2GRAY);
threshold(src_gray, binary, 0, 255, THRESH_BINARY | THRESH_TRIANGLE);//颜色单一时,使用THRESH_TRIANGLE比OTSU好
imshow("binary", binary);
//形态学操作
Mat kernel = getStructuringElement(MORPH_RECT, Size(5, 5));
dilate(binary, binary, kernel, Point(-1, -1), 4);
//距离变换
Mat dist;
bitwise_not(binary, binary);//取反
distanceTransform(binary, dist, CV_DIST_L2, 3);
normalize(dist, dist, 0, 1.0, NORM_MINMAX);
imshow("dist", dist);
//阈值化二值分割
//threshold(dist, dist,0.7,1.0,THRESH_BINARY);//对距离进行筛选,去除边缘部分
//normalize(dist, dist, 0, 255, NORM_MINMAX);
Mat dist_8U;
dist.convertTo(dist_8U, CV_8U);
adaptiveThreshold(dist_8U, dist_8U, 255, ADAPTIVE_THRESH_GAUSSIAN_C, THRESH_BINARY, 85, 0.0);//自适应阈值,代替上面的阈值操作
//形态学操作,使得断开部分连接
kernel = getStructuringElement(MORPH_RECT, Size(5, 5), Point(-1, -1));
dilate(dist_8U, dist_8U, kernel, Point(-1, -1), 3);
imshow("dist_8U", dist_8U);
// 连通区域计数
vector
findContours(dist_8U, contours, CV_RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
// draw result
Mat markers = Mat::zeros(src.size(), CV_8UC3);
RNG rng(12345);
for (size_t t = 0; t < contours.size(); t++) {
drawContours(markers, contours, static_cast
-1, 8, Mat());
}
printf("number of corns : %d", contours.size());
imshow("Final result", markers);
waitKey(0);
return 0;
}
P72-P75 透视校正:拍摄/扫描出来的图片倾斜,校正成正向图形********
# include
# include
# include
using namespace cv;
using namespace std;
int main(int agrc, char** agrv)
{
Mat src = imread("C:/Users/25503/Desktop/522.png");
if (src.empty())
{
printf("could not load image...\n");
return 0;
}
namedWindow("input image", CV_WINDOW_AUTOSIZE);
imshow("input image", src);
//二值处理
Mat gray_src, binary, dst;
cvtColor(src, gray_src, COLOR_BGR2GRAY);
threshold(gray_src, binary, 0, 255, THRESH_BINARY | THRESH_OTSU);//可以将THRESH_BINARY转化为THRESH_BINARY_INV
imshow("binary image", binary);
//形态学操作
Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));
morphologyEx(binary, dst, MORPH_CLOSE, kernel, Point(-1, -1), 3);
imshow("morphology", dst);
//轮廓发现
bitwise_not(dst, dst, Mat());
vector
vector
findContours(dst, contours, hireachy, CV_RETR_TREE, CHAIN_APPROX_SIMPLE, Point());
//轮廓绘制
int width = src.cols;
int height = src.rows;
Mat drawImage = Mat::zeros(src.size(), CV_8UC3);
for (size_t t = 0; t < contours.size(); t++)
{
Rect rect = boundingRect(contours[t]);
if (rect.width > width / 2 && rect.width < width - 5)
{
drawContours(drawImage, contours, static_cast
}
}
imshow("contours", drawImage);
vector
Mat contourImg;
int accu = min(width*0.5, height*0.5);
cvtColor(drawImage, contourImg, COLOR_BGR2GRAY);
HoughLinesP(contourImg, lines, 1, CV_PI / 180.0, accu, accu, 0);
Mat linesImage = Mat::zeros(src.size(), CV_8UC3);
for (size_t t = 0; t < lines.size(); t++)
{
Vec4i In = lines[t];
line(linesImage, Point(In[0], In[1]), Point(In[2], In[3]), Scalar(0, 0, 255), 2, 8, 0);
}
printf("number of lines :%d", lines.size());
imshow("lines image", linesImage);
//寻找与定位上下左右四条直线
int deltah = 0;
Vec4i topLine, bottomLine;
Vec4i leftLine, rightLine;
for (int i = 0; i < lines.size(); i++)
{
Vec4i In = lines[i];
deltah = abs(In[3] - In[1]);
if (In[3] < height / 2.0 && In[1] < height / 2.0 && deltah < accu - 1)
{
topLine = lines[i];
}
if (In[3] > height / 2.0 && In[1] > height / 2.0 && deltah < accu - 1)
{
bottomLine = lines[i];
}
if (In[0] < width / 2.0 && In[2]
leftLine = lines[i];
}
if (In[0] > width / 2.0 && In[2] > width / 2.0)
{
rightLine = lines[i];
}
}
cout << "top line:p1(x,y) =" << topLine[0] << "," << topLine[1] << "p2(x,y) =" << topLine[2] << "," << topLine[3] << endl;
cout << "bottom line:p1(x,y) =" << bottomLine[0] << "," << bottomLine[1] << "p2(x,y) =" << bottomLine[2] << "," << bottomLine[3] << endl;
cout << "left line:p1(x,y) =" << leftLine[0] << "," << leftLine[1] << "p2(x,y) =" << leftLine[2] << "," << leftLine[3] << endl;
cout << "right line:p1(x,y) =" << rightLine[0] << "," << rightLine[1] << "p2(x,y) =" << rightLine[2] << "," << rightLine[3] << endl;
//拟合四条直线方程
float k1, c1;
k1 = float(topLine[3] - topLine[1]) / float(topLine[2] - topLine[0]);
c1 = topLine[1] - k1 * topLine[0];
float k2, c2;
k2 = float(topLine[3] - topLine[1]) / float(topLine[2] - topLine[0]);
c2 = topLine[1] - k2 * topLine[0];
float k3, c3;
k3 = float(topLine[3] - topLine[1]) / float(topLine[2] - topLine[0]);
c3 = topLine[1] - k3 * topLine[0];
float k4, c4;
k4 = float(topLine[3] - topLine[1]) / float(topLine[2] - topLine[0]);
c4 = topLine[1] - k4 * topLine[0];
//四条直线交点
Point p1;//左上角点
p1.x = static_cast
p1.y = static_cast
Point p2;//右上角点
p2.x = static_cast
p2.y = static_cast
Point p3;//左下角点
p3.x = static_cast
p3.y = static_cast
Point p4;//右下角点
p4.x = static_cast
p4.y = static_cast
cout << "p1(x,y) =" << p1.x << "," << p1.y << endl;
cout << "p2(x,y) =" << p2.x << "," << p2.y << endl;
cout << "p3(x,y) =" << p3.x << "," << p3.y << endl;
cout << "p4(x,y) =" << p4.x << "," << p4.y << endl;
//显示四个点坐标
circle(linesImage, p1, 2, Scalar(255, 0, 0), 2, 8, 0);
circle(linesImage, p2, 2, Scalar(255, 0, 0), 2, 8, 0);
circle(linesImage, p3, 2, Scalar(255, 0, 0), 2, 8, 0);
circle(linesImage, p4, 2, Scalar(255, 0, 0), 2, 8, 0);
line(linesImage, Point(topLine[0], topLine[1]), Point(topLine[2], topLine[3]), Scalar(0, 255, 0), 2, 8, 0);
imshow("four corners", linesImage);
//透视变换
vector
src_corners[0] = p1;
src_corners[1] = p2;
src_corners[2] = p3;
src_corners[3] = p4;
vector
dst_corners[0] = Point(0, 0);
dst_corners[1] = Point(width, 0);
dst_corners[2] = Point(0, height);
dst_corners[3] = Point(width,height);
//获取透视变换矩阵warpmatrix
Mat resultImage;
Mat warpmatrix = getPerspectiveTransform(src_corners, dst_corners);
warpPerspective(src, resultImage, warpmatrix, resultImage.size(), INTER_LINEAR);
namedWindow("Final Result", CV_WINDOW_AUTOSIZE);
imshow("Final Result", resultImage);
waitKey(0);
return 0;
}
P76 对象提取与测量(代码与P68-P69相同)
P77级联分类器训练与使用实战概述
P78 Haar与LBP级联分类器(例如,人脸识别、分苹果案例)********************(基于图片)成功
# include
# include
using namespace cv;
using namespace std;
String fileName = "D:/Opencv3.4.6_build/install/etc/haarcascades/haarcascade_frontalface_alt.xml";//人脸库,也可以加上眼睛
CascadeClassifier face_classifier;
int main(int agrc, char** agrv)
{
if (!face_classifier.load(fileName))
{
printf("could not load face feature data...\n");
return -1;
}
Mat src = imread("C:/Users/25503/Desktop/327.jpg");
if (src.empty())
{
printf("could not load image...\n");
return -1;
}
Mat gray;
cvtColor(src, gray, COLOR_BGR2GRAY);
equalizeHist(gray, gray);
vector
face_classifier.detectMultiScale(gray, faces, 1.2, 3, 0, Size(24, 24));
for (size_t t = 0; t < faces.size(); t++)
{
rectangle(src, faces[static_cast
}
namedWindow("detect faces", CV_WINDOW_AUTOSIZE);
imshow("detect faces", src);
waitKey(0);
return 0;
}
P79 Haar与LBP级联分类器(人脸识别)************(基于摄像头)
P79-(1)基于摄像头识别人脸***********成功
# include
# include
using namespace cv;
using namespace std;
CascadeClassifier face_cascader;
String filename = "D:/Opencv3.4.6_build/install/etc/haarcascades/haarcascade_frontalface_alt.xml";
int main(int agrc, char** agrv)
{
if (!face_cascader.load(filename))
{
printf("could not load face feature data...\n");
return -1;
}
namedWindow("camera-demo", CV_WINDOW_AUTOSIZE);
VideoCapture capture(0);
Mat frame;
Mat gray;
vector
while (capture.read(frame))
{
cvtColor(frame, gray, COLOR_BGR2GRAY);
equalizeHist(gray, gray);
face_cascader.detectMultiScale(gray, faces, 1.2, 3, 0, Size(30, 30));
for (size_t t = 0; t < faces.size(); t++)
{
rectangle(frame, faces[static_cast
}
imshow("camera-demo", frame);
char c = waitKey(30);
if (c == 27)
{
break;
}
}
waitKey(0);
return 0;
}
P79-(2)基于摄像头识别人脸+人眼睛************成功
# include
# include
using namespace cv;
using namespace std;
CascadeClassifier face_cascader;
CascadeClassifier eye_cascader;
String facefile = "D:/Opencv3.4.6_build/install/etc/haarcascades/haarcascade_frontalface_alt.xml";
String eyefile = "D:/Opencv3.4.6_build/install/etc/haarcascades/haarcascade_eye.xml";
int main(int agrc, char** agrv)
{
if (!face_cascader.load(facefile))
{
printf("could not load face feature data...\n");
return -1;
}
if (!eye_cascader.load(eyefile))
{
printf("could not load face feature data...\n");
return -1;
}
namedWindow("camera-demo", CV_WINDOW_AUTOSIZE);
VideoCapture capture(0);
Mat frame;
Mat gray;
vector
vector
while (capture.read(frame))
{
cvtColor(frame, gray, COLOR_BGR2GRAY);
equalizeHist(gray, gray);
face_cascader.detectMultiScale(gray, faces, 1.2, 3, 0, Size(30, 30));
for (size_t t = 0; t < faces.size(); t++)
{
Rect roi;//定位在脸部范围
roi.x = faces[static_cast
roi.y = faces[static_cast
roi.width = faces[static_cast
roi.height = faces[static_cast
Mat faceROI = frame(roi);
eye_cascader.detectMultiScale(faceROI, eyes, 1.2, 3, 0, Size(20, 20));
for (size_t k = 0; k < eyes.size(); k++)
{
Rect rect;
rect.x = faces[static_cast
rect.y = faces[static_cast
rect.width = eyes[k].width;
rect.height = eyes[k].height;
rectangle(frame, rect, Scalar(0, 255, 255), 2, 8, 0);
}
rectangle(frame, faces[static_cast
}
imshow("camera-demo", frame);
char c = waitKey(30);
if (c == 27)
{
break;
}
}
waitKey(0);
return 0;
}
P79-(3) 基于摄像头识别人脸+嘴部(博士任务)
P80 图像分割概述
P81-P83 Kmeans方法-原理、数据聚类、图像分割
(1) Kmeans数据分类程序代码:
# include
# include
using namespace cv;
using namespace std;
int main(int agrc, char** agrv)
{
Mat img(500, 500, CV_8UC3);
RNG rng(12345);
Scalar colorTab[] = {
Scalar(0,0,255),
Scalar(0,255,0),
Scalar(255,0,0),
Scalar(0,255,255),
Scalar(255,0,255)
};
int numCluster = rng.uniform(2, 5);
printf("number of clusters:%d\n", numCluster);
int sampleCount = rng.uniform(5, 1000);
Mat points(sampleCount, 1, CV_32FC2);
Mat labels;
Mat centers;
//生成随机数
for (int k = 0; k < numCluster; k++)
{
Point center;
center.x = rng.uniform(0, img.cols);
center.y = rng.uniform(0, img.rows);
Mat pointChunk = points.rowRange(k*sampleCount / numCluster, k == numCluster - 1 ? sampleCount:(k + 1)*sampleCount / numCluster);
rng.fill(pointChunk, RNG::NORMAL, Scalar(center.x, center.y), Scalar(img.cols*0.05, img.rows*0.05));
}
randShuffle(points, 1, &rng);
//使用KMeans
kmeans(points, numCluster, labels, TermCriteria(TermCriteria::EPS + TermCriteria::COUNT, 10, 0.1), 3, KMEANS_PP_CENTERS, centers);
//用不同颜色显示分类
img = Scalar::all(255);
for (int i = 0; i < sampleCount; i++)
{
int index = labels.at
Point p = points.at
circle(img, p, 2, colorTab[index], -1, 8);
}
//每个聚类的中心来绘制圆
for (int i = 0; i < centers.rows; i++)
{
int x = centers.at
int y = centers.at
printf("c.x =%d, c.y =%d", x, y);
circle(img, Point(x, y), 40, colorTab[i], 1, LINE_AA);
}
imshow("KMeans-Data-Demo", img);
waitKey(0);
return 0;
}
(2) Kmens对图像进行分割程序代码:******
# include
# include
using namespace cv;
using namespace std;
int main(int agrc, char** agrv)
{
Mat src = imread("C:/Users/25503/Desktop/888.png");
if (src.empty())
{
printf("could not load image...\n");
return -1;
}
namedWindow("input image", CV_WINDOW_AUTOSIZE);
imshow("input image", src);
Scalar colorTab[] =
{
Scalar(0,0,255),
Scalar(0,255,0),
Scalar(255,0,0),
Scalar(0,255,255),
Scalar(255,0,255)
};
int width = src.cols;
int height = src.rows;
int dims = src.channels();
//初始化定义
int sampleCount = width * height;
int clusterCount = 4;
Mat points(sampleCount, dims, CV_32F, Scalar(10));
Mat labels;
Mat centers(clusterCount, 1, points.type());
//RGB数据转换到样本数据
int index = 0;
for (int row = 0; row < height; row++)
{
for (int col = 0; col < width; col++)
{
index = row * width + col;
Vec3b bgr = src.at
points.at
points.at
points.at
}
}
//运行K-Means
TermCriteria criteria = TermCriteria(TermCriteria::EPS + TermCriteria::COUNT, 10, 0.1);
kmeans(points, clusterCount, labels, criteria, 3, KMEANS_PP_CENTERS, centers);
//显示图像分割结果
Mat result = Mat::zeros(src.size(), src.type());
for (int row = 0; row < height; row++)
{
for (int col = 0; col < width; col++)
{
index = row * width + col;
int label = labels.at
result.at
result.at
result.at
}
}
/*//每个聚类的中心来绘制圆
for (int i = 0; i < centers.rows; i++)
{
int x = centers.at
int y = centers.at
printf("c.x =%d, c.y =%d", x, y);
circle(result, Point(x, y), 40, colorTab[i], 1, LINE_AA);
}
*/
imshow("KMeans image Segmentation Demo", result);
waitKey(0);
return 0;
}
P84 高斯混合模型(GMM)方法原理:
P85 高斯混合模型(GMM)进行图像分割处理:
#include
#include
using namespace std;
using namespace cv;
int main()
{
Mat srcImg = imread("C:/Users/25503/Desktop/888.png");
imshow("srcImg", srcImg);
Scalar colorsTab[] = {
Scalar(255, 0, 0),
Scalar(0, 255, 0),
Scalar(0, 0, 255),
Scalar(255, 255, 0)
};
int width = srcImg.cols;
int height = srcImg.rows;
int dims = srcImg.channels();
int numCluster = 4;
int numSample = width * height;
Mat points(numSample, dims, CV_64FC1);//在EM中数据是64位的
Mat labels;
// 图像RGB像素数据转换为样本数据
int index = 0;
for (int row = 0; row < height; row++) // 这里的步骤与KMeans是一样的
{
for (int col = 0; col < width; col++)
{
index = row * width + col;
Vec3b bgr = srcImg.at
points.at
points.at
points.at
}
}
double time0 = getTickCount();
//EM Cluster Train
Ptr
em_model->setClustersNumber(numCluster); // 设置分类数
em_model->setCovarianceMatrixType(ml::EM::COV_MAT_SPHERICAL); // 协方差矩阵类型
em_model->setTermCriteria(TermCriteria(TermCriteria::EPS + TermCriteria::COUNT, 100, 0.1)); // 迭代条件,EM训练比KMeans耗时,可能会不收敛,所以迭代次数设大点
em_model->trainEM(points, noArray(), labels, noArray()); // EM训练,获得分类结果,参数labels与KMeans的labels参数意思一样,速度比KMeans要慢很多
cout << "train time=" << (getTickCount() - time0) / getTickFrequency() << endl; // train time=10425.8 训练所需的时间很长
// 对每个像素标记颜色与显示
Mat result_nopredict = Mat::zeros(srcImg.size(), CV_8UC3);
Mat result_predict = Mat::zeros(srcImg.size(), CV_8UC3);
Mat sample(dims, 1, CV_64FC1); // 也只能用 CV_64F
time0 = getTickCount();
int r = 0, g = 0, b = 0;
for (int row = 0; row < height; row++)
{
for (int col = 0; col < width; col++)
{
// 获取训练的分类结果,放到 result_nopredict 中
index = row * width + col;
int label = labels.at
Scalar c = colorsTab[label];
result_nopredict.at
result_nopredict.at
result_nopredict.at
// 通过预言获得分类结果,因为EM训练用的是src的颜色数据,所以用src的颜色数据做预言,得到的结果与 result_nopredict 是一模一样的
b = srcImg.at
g = srcImg.at
r = srcImg.at
sample.at
sample.at
sample.at
Vec2d predict = em_model->predict2(sample, noArray()); // 预言,预言的时间是很短的
int response = cvRound(predict[1]); // response 就是目标颜色数据在EM训练中预言的分类
c = colorsTab[response];
result_predict.at
result_predict.at
result_predict.at
}
}
printf("execution time(ms) : %.2f\n", (getTickCount() - time0) / getTickFrequency()); // execution time(ms) : 1600.31
imshow("EM-Segmentation nopredict", result_nopredict); // 从效果看,KMeans更好些
imshow("EM-Segmentation predict", result_predict);
waitKey(0);
return 0;
}
P86-P89 分水岭分割原理、分离、计数
分水岭分割(硬币)程序代码:
# include
# include
using namespace cv;
using namespace std;
int main(int agrc, char** agrv)
{
Mat src = imread("C:/Users/25503/Desktop/7778.png");
if (src.empty())
{
printf("could not load image...\n");
return -1;
}
namedWindow("input image", CV_WINDOW_AUTOSIZE);
imshow("input image", src);
//中间填充
Mat gray, binary, shifted;
pyrMeanShiftFiltering(src, shifted, 21, 51);
imshow("shifted", shifted);
//二值化处理
cvtColor(shifted, gray, COLOR_BGR2GRAY);
threshold(gray, binary, 0, 255, THRESH_BINARY | THRESH_OTSU);
imshow("binary", binary);
//distance transform
Mat dist;
distanceTransform(binary, dist, DistanceTypes::DIST_L2, 3, CV_32F);
normalize(dist, dist, 0, 1, NORM_MINMAX);
imshow("distance transform result", dist);
//binary
threshold(dist, dist, 0.4, 1, THRESH_BINARY);
imshow("distance binary", dist);
//markers
Mat dist_m;
dist.convertTo(dist_m, CV_8U);
vector
findContours(dist_m, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE, Point(0, 0));
//create markers
Mat markers = Mat::zeros(src.size(), CV_32SC1);
for (size_t t = 0; t < contours.size(); t++)
{
drawContours(markers, contours, static_cast
}
circle(markers, Point(5, 5), 3, Scalar(255), -1);
imshow("markers", markers * 100000);
//形态学操作-彩色图像,目的是去掉干扰,让结果更好
Mat k = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));
morphologyEx(src, src, MORPH_ERODE, k);
//完成分水岭变换
watershed(src, markers);
Mat mark = Mat::zeros(markers.size(), CV_8UC1);
markers.convertTo(mark, CV_8UC1);
bitwise_not(mark, mark, Mat());
imshow("watershed result",mark);
//generate random color
vector
for (size_t i = 0; i < contours.size();i++)
{
int r = theRNG().uniform(0, 255);
int g = theRNG().uniform(0, 255);
int b = theRNG().uniform(0, 255);
colors.push_back(Vec3b((uchar)b, (uchar)g, (uchar)r));
}
//颜色填充与最终显示
Mat dst = Mat::zeros(markers.size(), CV_8UC3);
int index = 0;
for (int row = 0; row < markers.rows; row++)
{
for (int col = 0; col < markers.cols; col++)
{
index = markers.at
if (index > 0 && index <= contours.size())
{
dst.at
}
else
{
dst.at
}
}
}
imshow("Final Result", dst);
printf("number of objects:\n %d", contours.size());
waitKey(0);
return 0;
}
P90 -P91 Grabcut原理与演示应用---框选图像分割内容->抠图
//鼠标选定方框后,按下键盘n键,然后按下enter键,便可进行分割。
#include
#include
#include
using namespace cv;
using namespace std;
int numRun = 0;
Rect rect;
bool init = false;
Mat src, image;
Mat mask, bgModel, fgModel;//mask,背景,前景
const char* winTitle = "input image";
void onMouse(int event, int x, int y, int flags, void* param);
void setROIMask();
void showImage();
void runGrabCut();
int main(int argc, char** argv) {
src = imread("C:/Users/25503/Desktop/7778.png", 1);
if (src.empty()) {
printf("could not load image...\n");
return -1;
}
mask.create(src.size(), CV_8UC1);
mask.setTo(Scalar::all(GC_BGD));
namedWindow(winTitle, CV_WINDOW_AUTOSIZE);//
setMouseCallback(winTitle, onMouse, 0);//设置鼠标反馈事件
imshow(winTitle, src);
while (true) {
char c = (char)waitKey(0);
if (c == 'n') {
runGrabCut();//运行GrabCut算法
numRun++;
showImage();
printf("current iteative times : %d\n", numRun);//当前迭代次数
}
if ((int)c == 27) {
break;
}
}
waitKey(0);
return 0;
}
void showImage() {
Mat result, binMask;
binMask.create(mask.size(), CV_8UC1);
binMask = mask & 1;
if (init) {
src.copyTo(result, binMask);
}
else {
src.copyTo(result);//将src图像拷贝到result中
}
imwrite("tx2.png", result);
rectangle(result, rect, Scalar(0, 0, 255), 2, 8);//在result上绘制红色矩形框rect
imshow(winTitle, result);
}
void setROIMask() {
// GC_FGD = 1
// GC_BGD =0;
// GC_PR_FGD = 3
// GC_PR_BGD = 2
mask.setTo(GC_BGD);
rect.x = max(0, rect.x);
rect.y = max(0, rect.y);
rect.width = min(rect.width, src.cols - rect.x);
rect.height = min(rect.height, src.rows - rect.y);
mask(rect).setTo(Scalar(GC_PR_FGD));
}
//鼠标事件函数
void onMouse(int event, int x, int y, int flags, void* param) {
switch (event)
{
case EVENT_LBUTTONDOWN://鼠标左键按下
rect.x = x;//矩形左上角x,y坐标
rect.y = y;
rect.width = 1;//矩形线条宽度、高度
rect.height = 1;
init = false;
numRun = 0;
break;
case EVENT_MOUSEMOVE://鼠标移动
if (flags & EVENT_FLAG_LBUTTON) {
rect = Rect(Point(rect.x, rect.y), Point(x, y));
showImage();//显示带矩形框的图像
}
break;
case EVENT_LBUTTONUP://鼠标左键松开
if (rect.width > 1 && rect.height > 1) {
setROIMask();
showImage();
}
break;
default:
break;
}
}
//运行GrabCut函数
void runGrabCut() {
if (rect.width < 2 || rect.height < 2) {
return;
}
if (init) {
grabCut(src, mask, rect, bgModel, fgModel, 1);
} {
grabCut(src, mask, rect, bgModel, fgModel, 1, GC_INIT_WITH_RECT);
init = true;
}
}
P92-P93 证件照背景替换*******
#include
#include
using namespace std;
using namespace cv;
void ChangeImgBG();
Mat HandleImgData(Mat& img);
/*
图片背景替换
知识点:分水岭分割、高斯模糊
处理步骤:数据组装-KMeans分割-背景消除-生成遮罩-模糊-输出
*/
void ChangeImgBG()
{
const char* win1 = "原图";
const char* win2 = "腐蚀图";
const char* win3 = "高斯模糊图";
const char* win4 = "换底图";
//WINDOW_NORMAL设置了这个值,用户便可以改变窗口的大小(没有限制)
//WINDOW_AUTOSIZE如果设置了这个值,窗口大小会自动调整以适应所显示的图像,并且不能手动改变窗口大小.
namedWindow(win1, WINDOW_NORMAL);//创建窗口 win1
namedWindow(win2, WINDOW_NORMAL);//创建窗口 win2
namedWindow(win3, WINDOW_NORMAL);//创建窗口 win3
namedWindow(win4, WINDOW_NORMAL);//创建窗口 win4
Mat img1, img2, img3;
//加载图片
img1 = imread("C:/Users/25503/Desktop/樊玉和.jpg");//读入要处理的图片//图片放在工程目录下,与 .cpp文件同目录
if (img1.empty())
{
cout << "image not found..." << endl;
exit(0);//如果图片不存在,退出程序
}
img2 = img1.clone();
//显示原始图片
imshow(win1, img1);
//组装数据
Mat points = HandleImgData(img1);
//Kmeans处理
int numCluster = 4;
Mat labels;
Mat centers;
TermCriteria termCriteria = TermCriteria(TermCriteria::EPS + TermCriteria::COUNT, 10, 0.1);
kmeans(points, numCluster, labels, termCriteria, 3, KMEANS_PP_CENTERS, centers);
//遮罩
Mat mask = Mat::zeros(img1.size(), CV_8UC1);
int index = img1.rows * 2 + 2;
int cindex = labels.at
int height = img1.rows;
int width = img1.cols;
for (int row = 0; row < height; row++)
{
for (int col = 0; col < width; col++)
{
index = row * width + col;
int label = labels.at
if (label == cindex)
{
img2.at
img2.at
img2.at
mask.at
}
else
{
mask.at
}
}
}
//腐蚀
Mat k = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));
erode(mask, mask, k);
imshow(win2, mask);
//高斯模糊
GaussianBlur(mask, mask, Size(3, 3), 0, 0);
imshow(win3, mask);
//通道混合
RNG rng(12345);
//背景颜色调整
Vec3b color; //RGB三原色可以任意组合 ,注意下面的数组顺序是BGR
/*color[0] = rng.uniform(255, 255);
color[1] = rng.uniform(255, 255);
color[2] = rng.uniform(255, 255);*/
color[0] = 255; //B
color[1] = 255; //G
color[2] = 255; //R
Mat result(img1.size(), img1.type());
double d1 = 0.0;
int r = 0, g = 0, b = 0;
int r1 = 0, g1 = 0, b1 = 0;
int r2 = 0, g2 = 0, b2 = 0;
for (int row = 0; row < height; row++)
{
for (int col = 0; col < width; col++)
{
int m = mask.at
if (m == 255)
{
result.at
}
else if (m == 0)
{
result.at
}
else
{
d1 = m / 255.0;
b1 = img1.at
g1 = img1.at
r1 = img1.at
b2 = color[0];
g2 = color[1];
r2 = color[2];
b = b1 * d1 + b2 * (1.0 - d1);
g = g1 * d1 + g2 * (1.0 - d1);
r = r1 * d1 + r2 * (1.0 - d1);
result.at
result.at
result.at
}
}
}
//输出
imshow(win2, mask);
imshow(win3, img2);
imshow(win4, result);
//保存处理后的图片
imwrite("result1.jpg", result);//换底后的图片以result1.jpg保存在.cpp文件目录下
}
//组装样本数据
Mat HandleImgData(Mat& img)
{
int width = img.cols;
int height = img.rows;
int count1 = width * height;
int channels1 = img.channels();
Mat points(count1, channels1, CV_32F, Scalar(10));
int index = 0;
for (int row = 0; row < height; row++)
{
for (int col = 0; col < width; col++)
{
index = row * width + col;
Vec3b bgr = img.at
points.at
points.at
points.at
}
}
return points;
}
int main()
{
ChangeImgBG();//换底
waitKey(0);
return 0;
}
P94-P95 绿色背景视频抠图
#include
#include "opencv2/opencv.hpp"
using namespace cv;
using namespace std;
const char* title = "input video";
const char* resultWin = "result voide";
Mat background_01;
Mat replace_and_blend(Mat &frame, Mat &mask);
//视频抠图
int main(int agrc, char** grgv)
{
background_01 = imread("C:/Users/25503/Desktop/2021.jpg");
if (background_01.empty())
{
printf("could not load image ...");
return -1;
}
VideoCapture capture;
// capture.open("../image/1113.jpg")
capture.open(0);
if (!capture.isOpened())
{
printf("could not load video ...");
return -1;
}
int nCount = 0;
Mat frame, hsv, mask;
while (capture.read(frame))
{
cvtColor(frame, hsv, CV_BGR2HSV);
inRange(hsv, Scalar(35, 44, 46), Scalar(155, 255, 255), mask);
//形态学操作
Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));
morphologyEx(mask, mask, MORPH_CLOSE, kernel);
erode(mask, mask, kernel);
GaussianBlur(mask, mask, Size(3, 3), 0, 0);
Mat result = replace_and_blend(frame, mask);
char c = waitKey(1);
if (c == 27)
{
break;
}
imshow("mask", mask);
imshow("result", result);
imshow(title, frame);
}
waitKey(0);
return -1;
}
Mat replace_and_blend(Mat &frame, Mat &mask)
{
Mat reslut = Mat::zeros(frame.size(), frame.type());
int h = frame.rows;
int w = frame.cols;
int dims = frame.channels();
//feplace and blend
int m = 0;
double wt = 0;
int r = 0, g = 0, b = 0;
int r1 = 0, g1 = 0, b1 = 0;
int r2 = 0, g2 = 0, b2 = 0;
for (int row = 0; row < h; row++)
{
uchar *current = frame.ptr
uchar *bgrow = background_01.ptr
uchar *maskrow = mask.ptr
uchar *targetrow = reslut.ptr
for (int col = 0; col < w; col++)
{
m = *maskrow++;
if (m == 255)//背景
{
*targetrow++ = *bgrow++;
*targetrow++ = *bgrow++;
*targetrow++ = *bgrow++;
current += 3;
}
else if (m == 0) {//前景
*targetrow++ = *current++;
*targetrow++ = *current++;
*targetrow++ = *current++;
bgrow += 3;
}
else {
b1 = *bgrow++;
g1 = *bgrow++;
r1 = *bgrow++;
b2 = *current++;
g2 = *current++;
r2 = *current++;
//权重
wt = m / 255.0;
//混合
b = b1 * wt + b2 * (1.0 - wt);
g = g1 * wt + g2 * (1.0 - wt);
r = r1 * wt + r2 * (1.0 - wt);
*targetrow++ = b;
*targetrow++ = g;
*targetrow++ = r;
}
}
}
return reslut;
}
P96 视频分析与对象跟踪实践(环境配置搭建)
P97-P98 视频读写
#include
#include
using namespace cv;
int main()
{
VideoCapture capture;
capture.open(0);
if (!capture.isOpened())
{
printf("can not open ...\n");
return -1;
}
Size size = Size(capture.get(CV_CAP_PROP_FRAME_WIDTH), capture.get(CV_CAP_PROP_FRAME_HEIGHT));
VideoWriter writer;
writer.open("E:/image/a2.avi", CV_FOURCC('M', 'J', 'P', 'G'), 10, size, true);
Mat frame, gray;
namedWindow("output", CV_WINDOW_AUTOSIZE);
while (capture.read(frame))
{
//转换为黑白图像
cvtColor(frame, gray, COLOR_BGR2GRAY);
//二值化处理
threshold(gray, gray, 0, 255, THRESH_BINARY | THRESH_OTSU);
cvtColor(gray, gray, COLOR_GRAY2BGR);
imshow("output", gray);
writer.write(gray);
waitKey(10);
}
waitKey(0);
capture.release();
return 0;
}
P99-P100 背景消除建模(BSM)2021/1/14
#include
#include
using namespace cv;
using namespace std;
int main(int argc, char**) {
VideoCapture capture(0);//调用摄像头
//capture.open("F:/video_003.avi");
if (!capture.isOpened()) {
printf("could not find the video file...\n");
return -1;
}
// create windows
Mat frame;
Mat bsmaskMOG2, bsmaskKNN;
namedWindow("input video", CV_WINDOW_AUTOSIZE);
namedWindow("MOG2", CV_WINDOW_AUTOSIZE);
namedWindow("KNN Model", CV_WINDOW_AUTOSIZE);
//形态学开操作
Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));
// intialization BS
//高斯混合模型背景建模
Ptr
//KNN-K个最近邻
Ptr
while (capture.read(frame)) {
imshow("input video", frame);
// MOG BS
pMOG2->apply(frame, bsmaskMOG2);//
//形态学开操作去噪点
//对处理后的帧进行开操作,减少视频中较小的波动造成的影响
morphologyEx(bsmaskMOG2, bsmaskMOG2, MORPH_OPEN, kernel, Point(-1, -1));
imshow("MOG2", bsmaskMOG2);//高斯混合模型背景模型
// KNN BS mask
pKNN->apply(frame, bsmaskKNN);
morphologyEx(bsmaskKNN, bsmaskKNN, MORPH_OPEN, kernel, Point(-1, -1));//形态学开操作去噪点
imshow("KNN Model", bsmaskKNN);//KNN背景模型
char c = waitKey(50);
if (c == 27) {
break;
}
}
capture.release();
waitKey(0);
return 0;
}
P111-P112基于颜色的对象检测与跟踪***单目标
/*思路:inRange过滤、形态学操作提取、轮廓查找、外接矩形获取、位置标定*/
#include
#include
using namespace cv;
using namespace std;
void processFrame(Mat& img, Rect& rect);//绘制外接矩形
int main(int argc, char** argv)
{
Rect roi;//存储最大外接矩形的数据
VideoCapture capture(0);//调用摄像头
//VideoCapture capture;
//capture.open("D:/test/video_006.mp4");
if (!capture.isOpened())
{
cout << "视频文件未找到..." << endl;
return -1;
}
Mat frame, dst;
Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));
Mat kernel_dilite = getStructuringElement(MORPH_RECT, Size(7, 7), Point(-1, -1));
while (capture.read(frame))
{
//筛选出绿色
inRange(frame, Scalar(0, 127, 0), Scalar(120, 255, 120), dst);
//开操作去噪点
morphologyEx(dst, dst, MORPH_OPEN, kernel, Point(-1, -1), 1);
//膨胀操作把飞盘具体化的显示出来
dilate(dst, dst, kernel_dilite, Point(-1, -1), 2);
imshow("output video", dst);
processFrame(dst, roi);
rectangle(frame, roi, Scalar(0, 0, 255), 3, 8, 0);
imshow("input video", frame);
char c = waitKey(50);
if (c == 27)
{
break;
}
}
capture.release();
waitKey(0);
return 0;
}
void processFrame(Mat & img, Rect & rect)
{
//寻找外接轮廓
vector
vector
findContours(img, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE, Point(-1, -1));
double area = 0.0;
if (contours.size() > 0)
{
for (size_t i = 0; i < contours.size(); i++)
{
double contours_Area = contourArea(contours[static_cast
rect = boundingRect(contours[static_cast
if (contours_Area > area)
{
area = contours_Area;
}
}
}
else
{
rect.x = rect.y = rect.width = rect.height = 0;
}
}
P113-P116 光流对象跟踪****移动对象跟踪
(1)稀疏光流KLT
代码1 CSDN论坛代码*****只有结果显示,没有图像显示
#include
#include
#include
#include
#include
#include
#include
using namespace cv::face;
using namespace cv;
using namespace std;
using namespace cv::xfeatures2d;
Mat frame, gray;//当前帧
Mat prev_gray;//前一帧
vector
vector
vector
vector
vector
void detectFeatures(Mat &inFrame, Mat &ingray) // Shi-Tomas 角点检测
{
double maxCorners = 5000;
double qualitylevel = 0.01;
double minDistance = 10;
double blockSize = 3;
double k = 0.04;
goodFeaturesToTrack(ingray, features, maxCorners, qualitylevel, minDistance, Mat(), blockSize, false, k); // 算法很快,满足实时性要求
cout << "detect features : " << features.size() << endl;
}
void drawFeature(Mat&inFrame) {//绘制特征点
for (size_t t = 0; t < fpts[0].size(); t++) {
circle(inFrame, fpts[0][t], 2, Scalar(0, 0, 255), 2);
}
}
void drawTrackLines() // 在跟踪到的且移动了的特征点(光流)的开始跟踪的位置 到 当前跟踪到的位置之间绘制线段
{
for (size_t t = 0; t < fpts[1].size(); t++)
{
line(frame, iniPoints[t], fpts[1][t], Scalar(0, 255, 0), 1, 8, 0); // 绘制线段
circle(frame, fpts[1][t], 2, Scalar(0, 0, 255), 2, 8, 0);
}
}
void KLTrackFeature() {//稀疏光流跟踪,KTL
calcOpticalFlowPyrLK(prev_gray, gray, fpts[0], fpts[1], status, errors);
int k = 0;//保存跟踪到的特征点数,最后将特征点的尺寸重新设置为k
for (int i = 0; i < fpts[1].size(); i++) {
double dist = abs(fpts[0][i].x - fpts[1][i].x) + abs(fpts[0][i].y - fpts[1][i].y);
if (dist > 2 && status[i])//跟踪到的特征点,且距离移动了2以上的
{
iniPoints[k] = iniPoints[i];//将跟踪到的移动了的特征点在vector中连续起来,剔掉损失的和禁止不动的特征点(这些跟踪点在前面帧中)
fpts[1][k++] = fpts[1][i];//同上(只是这些跟踪点在当前帧中)
}
}
//保存特征点并绘制跟踪轨迹
iniPoints.resize(k);
fpts[1].resize(k);
drawTrackLines();
std::swap(fpts[1], fpts[0]);//交换,将此帧跟踪到特征点作为下一帧的待跟踪点
}
int main() {
//VideoCapture capture;
//capture.open("C:/Users/Administrator/Desktop/pic/3.avi");
VideoCapture capture(0);//调用摄像头
while (capture.read(frame)) {
cvtColor(frame, gray, COLOR_BGR2GRAY);
if (fpts[0].size() < 40) {//跟踪40个特征点,如果跟踪的时候损失了一些特征点,重新检测,追加
detectFeatures(frame, gray);
fpts[0].insert(fpts[0].end(), features.begin(), features.end());//追加带跟踪的特征点
iniPoints.insert(iniPoints.end(), features.begin(), features.end());
}
else
{
cout << "tracjing........" << endl;
}
if (prev_gray.empty())
gray.copyTo(prev_gray);//保存当前已帧,第一帧过完就不保存了
KLTrackFeature();//稀疏光流跟踪,KLT
drawFeature(frame);//绘制特征点
//更新前一帧数据
gray.copyTo(prev_gray);//只需要灰度图
imshow("src", frame);
}
waitKey(0);
}
(2)代码2 贾志刚老师教学视频代码****有显示,成功
// 程序描述:来自OpenCV安装目录下Samples文件夹中的官方示例程序-利用光流法进行运动目标检测
// 描述:包含程序所使用的头文件和命名空间
#include
#include
#include
#include
#include
#include
using namespace std;
using namespace cv;
// 描述:声明全局函数
void tracking(Mat &frame, Mat &output);
bool addNewPoints();
bool acceptTrackedPoint(int i);
// 描述:声明全局变量
string window_name = "optical flow tracking";
Mat gray; // 当前图片
Mat gray_prev; // 预测图片
vector
vector
vector
int maxCount = 500; // 检测的最大特征数
double qLevel = 0.01; // 特征检测的等级
double minDist = 10.0; // 两特征点之间的最小距离
vector
vector
//输出相应信息和OpenCV版本-----
static void helpinformation()
{
cout << "\n\n\t\t\t 光流法跟踪运动目标检测\n"
<< "\n\n\t\t\t 当前使用的OpenCV版本为:" << CV_VERSION
<< "\n\n";
}
//main( )函数,程序入口
int main()
{
Mat frame;
Mat result;
//加载使用的视频文件,放在项目程序运行文件下
//VideoCapture capture("1.avi");
VideoCapture capture(0);//调用摄像头
//显示信息函数
helpinformation();
// 摄像头读取文件开关
if (capture.isOpened())
{
while (true)
{
capture >> frame;
if (!frame.empty())
{
tracking(frame, result);
}
else
{
printf(" --(!) No captured frame -- Break!");
break;
}
int c = waitKey(50);
if ((char)c == 27)
{
break;
}
}
}
return 0;
}
// parameter: frame 输入的视频帧
// output 有跟踪结果的视频帧
void tracking(Mat &frame, Mat &output)
{
cvtColor(frame, gray, CV_BGR2GRAY);
frame.copyTo(output);
// 添加特征点
if (addNewPoints())
{
goodFeaturesToTrack(gray, features, maxCount, qLevel, minDist);
points[0].insert(points[0].end(), features.begin(), features.end());
initial.insert(initial.end(), features.begin(), features.end());
}
if (gray_prev.empty())
{
gray.copyTo(gray_prev);
}
// l-k光流法运动估计
calcOpticalFlowPyrLK(gray_prev, gray, points[0], points[1], status, err);
// 去掉一些不好的特征点
int k = 0;
for (size_t i = 0; i < points[1].size(); i++)
{
if (acceptTrackedPoint(i))
{
initial[k] = initial[i];
points[1][k++] = points[1][i];
}
}
points[1].resize(k);
initial.resize(k);
// 显示特征点和运动轨迹
for (size_t i = 0; i < points[1].size(); i++)
{
line(output, initial[i], points[1][i], Scalar(0, 0, 255));
circle(output, points[1][i], 3, Scalar(0, 255, 0), -1);
}
// 把当前跟踪结果作为下一此参考
swap(points[1], points[0]);
swap(gray_prev, gray);
imshow(window_name, output);
}
// 检测新点是否应该被添加
// return: 是否被添加标志
bool addNewPoints()
{
return points[0].size() <= 10;
}
//决定哪些跟踪点被接受
bool acceptTrackedPoint(int i)
{
return status[i] && ((abs(points[0][i].x - points[1][i].x) + abs(points[0][i].y - points[1][i].y)) > 2);
}
P117-P120 CAMShift 对象跟踪(对象跟踪扩展模块)
(1)教学视频相关代码---CAMShift 算法对象跟踪介绍:均值计算,密度最高点跟踪
#include
#include
#include
#include
using namespace cv;
using namespace std;
//HSV颜色范围
int smin = 40;
int vmin = 40;
int smax = 255;
int vmax = 255;
int bins = 16;
int main(int agrc, char** argv)
{
//VideoCapture capture;
//capture.open("视频路径");
VideoCapture capture(0);//调用摄像头
if (!capture.isOpened())
{
printf("could not find video data file...\n");
return -1;
}
namedWindow("CAMShift Tracking", CV_WINDOW_AUTOSIZE);
namedWindow("ROI Histogram", CV_WINDOW_AUTOSIZE);
bool firstRead = true;
float hrange[] = { 0,180 };
const float* hranges = hrange;
Rect selection;
Mat frame, hsv, hue, mask, hist, backprojection;
Mat drawImg = Mat::zeros(300, 300, CV_8UC3);
while (capture.read(frame))
{
if (firstRead)
{
Rect2d first = selectROI("CAMShift Tracking", frame);
selection.x = first.x;
selection.y = first.y;
selection.width = first.width;
selection.height = first.height;
printf("ROL.x =%d, ROL.y =%d, width =%d, height =%d", selection.x, selection.y, selection.width, selection.height);
//firstRead = false;
}
//convert to HSV
cvtColor(frame, hsv, COLOR_BGR2HSV);
inRange(hsv, Scalar(0, smin, vmin), Scalar(180, smax, vmax), mask);//筛选颜色
hue = Mat(hsv.size(), hsv.depth());
int channels[] = { 0,0 };
mixChannels(&hsv, 1, &hue, 1, channels, 1);
if (firstRead)
{
//calculate histogram -ROI直方图计算
Mat roi(hue, selection);
Mat maskroi(mask, selection);
calcHist(&roi, 1, 0, maskroi, hist, 1, &bins, &hranges);
normalize(hist, hist, 0, 255, NORM_MINMAX);
//show histogram
int binw = drawImg.cols / bins;
Mat colorIndex = Mat(1, bins, CV_8UC3);
for (int i = 0; i < bins; i++)
{
colorIndex.at
}
cvtColor(colorIndex, colorIndex, COLOR_HSV2BGR);
for (int i = 0; i < bins; i++)
{
int val = saturate_cast
rectangle(drawImg, Point(i*binw, drawImg.rows), Point((i + 1)*binw, drawImg.rows - val), Scalar(colorIndex.at
}
}
//back projection
calcBackProject(&hue, 1, 0, hist, backprojection, &hranges);
//CAMShift tracking
backprojection &= mask;
RotatedRect trackBox = CamShift(backprojection, selection, TermCriteria((TermCriteria::COUNT | TermCriteria::EPS), 10, 1));
// draw location on frame
ellipse(frame, trackBox, Scalar(0, 0, 255), 3, 8);//绘制红色椭圆,BGR
if (firstRead)
{
firstRead = false;
}
imshow("CAMShift Tracking", frame);
imshow("ROI Histogram", drawImg);
char c = waitKey(50);//ESC
if (c == 27)
{
break;
}
}
capture.release();
waitKey(0);
return 0;
}
(2) CSDN相应代码-CAMShift 算法对象跟踪*******跟踪效果极好
//Select a ROI and then press SPACE or ENTER button!
//Cancel the selection process by pressing c button!
#include
#include
using namespace cv;
using namespace std;
//HSV
int smin = 30;
int smax = 255;
int vmin = 40;
int vmax = 255;
//calcHist参数
int histSize = 16;//区间的个数
float hue_ranges[] = { 0,180 };
const float* ranges = hue_ranges;
int main(int argc, char** argv)
{
VideoCapture capture;
//capture.open(0);
capture.open(0);
if (!capture.isOpened())
{
cout << "could not load video..." << endl;
return -1;
}
bool firstRead = true;//用于判断是否第一次读取视频
Rect selection;//selectROI用鼠标选择的ROI区域
Mat frame, blur, hsv, mask, hue, temp_histogram, backprojection;
Mat Histogram = Mat::zeros(300, 300, CV_8UC3);
namedWindow("CAMShift Tracking", WINDOW_AUTOSIZE);
while (capture.read(frame))
{
if (firstRead)
{
//获取第一帧的ROI区域
Rect2d first_img = selectROI("CAMShift Tracking", frame);//在"CAMShift Tracking"窗口的frame图像上用鼠标选择ROI区域
selection.x = first_img.x;
selection.y = first_img.y;
selection.width = first_img.width;
selection.height = first_img.height;
cout << "ROI的x值为: " << selection.x << endl;
cout << "ROI的y值为: " << selection.y << endl;
cout << "ROI的width值为: " << selection.width << endl;
cout << "ROI的height值为: " << selection.height << endl;
}
GaussianBlur(frame, blur, Size(5, 5), 3, 3);//使用高斯滤波进行去噪
cvtColor(blur, hsv, COLOR_BGR2HSV);//转换到HSV空间
//测试矩阵frame的元素是否在其他两个矩阵的值之间//提取黄色
inRange(hsv, Scalar(0, smin, vmin), Scalar(180, smax, vmax), mask);
hue = Mat(hsv.size(), hsv.depth());
int channels[] = { 0,0 };//fromto映射//指定被复制通道与要复制到的位置组成的索引对
size_t npairs = 1; //指定被复制通道与要复制到的位置channels[]组成的索引对
mixChannels(&hsv, 1, &hue, 1, channels, npairs); //输入矩阵通道 重新排列到 输出矩阵通道(HSV中的H值)
if (firstRead)
{
//计算ROI直方图
Mat ROI(hue, selection);//Mat& image , Rect& roi
Mat MaskROI(mask, selection);
calcHist(&ROI, 1, 0, MaskROI, temp_histogram, 1, &histSize, &ranges);//计算直方图
normalize(temp_histogram, temp_histogram, 0, 255, NORM_MINMAX);//归一化
//显示直方图图像
int bins = Histogram.cols / histSize; //300/16 = 18.5 单个区间宽度
//定义一个缓冲单bins矩阵,1行16列,用于存放颜色数据,用于直方图histSize个bin的“染色”
Mat ColorIndex = Mat(1, histSize, CV_8UC3);//1行histSize=16列
for (int i = 0; i < histSize; i++)
{
ColorIndex.at
}
cvtColor(ColorIndex, ColorIndex, COLOR_HSV2BGR);
for (int j = 0; j < histSize; j++)
{
//value是直方图temp_histogram的相对Histogram的高度
//temp_histogram.at(i)获取了第i个bin直方图数据,除以255后得到百分比
//再乘以Histogram的行数就得到了相对高度,最后进行int的强制类型转换,转换为整数。
int value = saturate_cast
//之后使用rectangle()函数进行16个bin的绘制
//值得注意的是矩阵的坐标系以左上角为原点,y轴是向下的
//而需要展示给人看的直方图图案是左下角为原点,y轴向上的
//因此rectangle的两个标定点的纵坐标是Histogram.rows和(Histogram.rows - val)而不是0和val
rectangle(Histogram,
Point(j * bins, Histogram.rows), //矩阵对角点:左下角
Point((j + 1) * bins, Histogram.rows - value), //矩阵对角点:右上角
Scalar(ColorIndex.at
}
firstRead = false;//需要绘制第一帧的直方图
}
//直方图反向投影
/*void calcBackProject(
const Mat* images, //输入的数组
int nimages, //输入数组的个数
const int* channels, //需要统计的通道索引
InputArray hist, //输入的直方图
OutputArray backProject,//目标的反向投影
const float** ranges, //每一位数值的取值范围
double scale=1, //输出方向投影的缩放因子
bool uniform=true //指示直方图是否均匀的标识符
)
*/
//用来计算像素和直方图模型中像素吻合度的方法
calcBackProject(&hue, 1, 0, temp_histogram, backprojection, &ranges);
backprojection &= mask;//a&=b 即 a=a&b 其中&为位与运算//给b取了一个别名叫a,所有对b的操作都是直接作用于a
//CAMShift
RotatedRect trackBox = CamShift(
backprojection, //反向投影
selection,//矩形搜索框
TermCriteria((TermCriteria::COUNT | TermCriteria::EPS), 10, 1));//迭代中止条件
//绘制位置更新显示在frame上
//---------------------------------获取CamShift的返回值,是一个旋转矩形,以下为绘制跟踪结果的部分
ellipse(frame, trackBox, Scalar(255, 0, 255), 3, 8);//根据旋转矩形绘制一个椭圆形显示在图像上作为追踪结果。
Point2f vertices[4];//定义存储4个x,y变量的数组
trackBox.points(vertices);//将旋转矩形的四个顶点值传入数组
for (int i = 0; i < 4; i++)//绘制旋转矩形的四条边
line(frame, vertices[i], vertices[(i + 1) % 4], Scalar(0, 255, 0));
Rect brect = trackBox.boundingRect();//返回最小旋转角度为0的外接矩形
rectangle(frame, brect, Scalar(255, 0, 0));//绘制外接矩形
//----------------------------------
if (firstRead)
{
firstRead = false;
}
imshow("CAMShift Tracking", frame);
imshow("Histogram", Histogram);
char c = waitKey(1);
if (c == 27)
{
break;
}
}
capture.release();
waitKey(0);
//destroyAllWindows();
return 0;
}
P121视频中移动对象统计:也即统计移动物体的数量******项目可以考虑
(1) 教学视频代码演示****效果好
#include
#include
using namespace cv;
using namespace std;
int main(int agrc, char** agrv)
{
//VideoCapture capture;
//capture.open("读取视频地址");
VideoCapture capture(0);//调用摄像头
if (!capture.isOpened())
{
printf("could not load video data...\n");
return -1;
}
namedWindow("input video", CV_WINDOW_AUTOSIZE);
namedWindow("motion objects", CV_WINDOW_AUTOSIZE);
//初始BS模型
Ptr
Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));
vector
vector
int count = 0;
Mat frame, gray,mogMask;
while (capture.read(frame))
{
imshow("input video", frame);
pMOG2->apply(frame, mogMask);
threshold(mogMask, mogMask, 100, 255, THRESH_BINARY);
morphologyEx(mogMask, mogMask, MORPH_OPEN, kernel, Point(-1, -1));
findContours(mogMask, contours, hireachy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE, Point(0, 0));
count = 0;
char numText[8];
for (size_t t = 0; t < contours.size(); t++)
{
double area = contourArea(contours[t]);
if (area < 1000) continue;
Rect selection = boundingRect(contours[t]);
if (selection.width < 30 || selection.height < 30) continue;
count++;
rectangle(frame, selection, Scalar(0, 0, 255), 2, 8);
sprintf_s(numText, "%d", count);
putText(frame, numText, Point(selection.x, selection.y), CV_FONT_NORMAL, FONT_HERSHEY_PLAIN, Scalar(255,0,0),1, 8);
}
imshow("motion objects", frame);
char c = waitKey(50);
if (c == 27)//ESC
{
break;
}
}
capture.release();
waitKey(0);
return 0;
}
(2)CSDN代码-视频中移动对象统计
#include
#include
#include
#include
#include
#include
#include
using namespace cv::face;
using namespace cv;
using namespace std;
using namespace cv::xfeatures2d;
int main() {
//VideoCapture capture;
//capture.open("C:/Users/Administrator/Desktop/pic/3.avi");
VideoCapture capture(0);//调用摄像头
Ptr
Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3));
vector
vector
Mat frame, gray, mogmask;
while (capture.read(frame)) {
imshow("src", frame);
pMOG2->apply(frame, mogmask);
threshold(mogmask, mogmask, 100, 255, THRESH_BINARY);//二值化
morphologyEx(mogmask, mogmask, MORPH_OPEN, kernel);
findContours(mogmask, contours, hireachy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE, Point(0, 0));
cvtColor(mogmask, mogmask, COLOR_GRAY2BGR);
int count = 0;
char numText[8];
for (size_t t = 0; t < contours.size(); t++) {
double area = contourArea(contours[t]);//获取轮廓的面积
if (area < 100) continue;//忽略面积小的
Rect selection = boundingRect(contours[t]);
if (selection.width < 10 || selection.height < 10) contours;
count++;
rectangle(mogmask, selection, Scalar(0, 0, 255), 2);
sprintf_s(numText, "%d", count);
putText(mogmask, numText, Point(selection.x, selection.y), CV_FONT_NORMAL, FONT_HERSHEY_PLAIN, Scalar(255, 0, 0));
}
imshow("motion objects", mogmask);
char c = waitKey(50);
if (c == 27)//ESC
{
break;
}
}
capture.release();
waitKey(0);
return 0;
}
P122、 扩展模块中的跟踪方法介绍2021/1/20*****可以和上面的CamShift跟踪算法对比---单目标检测算法对比
KCF、BOOSTING、MIL、MEDIANFLOW、TLD跟踪算法
#include
#include
#include
using namespace cv;
using namespace std;
int main(int agrc, char** agrv)
{
//VideoCapture capture;
//capture.open("视频路径");
VideoCapture capture(0);//调用摄像头
if (!capture.isOpened())
{
printf("could not load video data...\n");
return -1;
}
Mat frame;
namedWindow("tracker demo", CV_WINDOW_AUTOSIZE);
Ptr
//Ptr
//Ptr
//Ptr
//Ptr
capture.read(frame);
Rect2d roi = selectROI("tracker demo", frame);
if (roi.width == 0 || roi.height == 0)
{
return -1;
}
tracker->init(frame, roi);
while (capture.read(frame))
{
tracker->update(frame, roi);
rectangle(frame, roi, Scalar(255, 0, 0), 2, 8, 0);
imshow("tracker demo", frame);
char c = waitKey(20);
if (c == 27)
{
break;
}
}
capture.release();
waitKey(0);
return 0;
}
P123、多对象目标跟踪******实际项目常用
(1) 、CSDN论坛上的多目标跟踪MultiTrack****成功
#include
#include
#include
#include
#include
#include
#include
using namespace std;
using namespace cv;
inline cv::Ptr
{
cv::Ptr
if (name == "KCF")
tracker = cv::TrackerKCF::create();
else if (name == "TLD")
tracker = cv::TrackerTLD::create();
else if (name == "BOOSTING")
tracker = cv::TrackerBoosting::create();
else if (name == "MEDIAN_FLOW")
tracker = cv::TrackerMedianFlow::create();
else if (name == "MIL")
tracker = cv::TrackerMIL::create();
else if (name == "GOTURN")
tracker = cv::TrackerGOTURN::create();
else if (name == "MOSSE")
tracker = cv::TrackerMOSSE::create();
else if (name == "CSRT")
tracker = cv::TrackerCSRT::create();
else
CV_Error(cv::Error::StsBadArg, "Invalid tracking algorithm name\n");
return tracker;
}
int main(int argc, char** argv) {
// set the default tracking algorithm
std::string trackingAlg = "MEDIAN_FLOW";
MultiTracker trackers;
// container of the tracked objects
vector
VideoCapture cap(0);
if (!cap.isOpened())
{
std::cout << "error open." << std::endl;
return -1;
}
Mat frame;
// get bounding box
cap >> frame;
//! [selectmulti]
vector
selectROIs("tracker", frame, ROIs);
//! [selectmulti]
//quit when the tracked object(s) is not provided
if (ROIs.size() < 1)
return 0;
// initialize the tracker
//! [init]
std::vector
for (size_t i = 0; i < ROIs.size(); i++)
{
algorithms.push_back(createTrackerByName(trackingAlg));
objects.push_back(ROIs[i]);
}
trackers.add(algorithms, frame, objects);
//! [init]
// do the tracking
printf("Start the tracking process, press ESC to quit.\n");
while (cap.isOpened()) {
cap >> frame;
//update the tracking result
trackers.update(frame);
// draw the tracked object
for (unsigned i = 0; i < trackers.getObjects().size(); i++)
rectangle(frame, trackers.getObjects()[i], Scalar(0, 0, 255), 2, 1);//BGR
// show image with the tracked object
imshow("tracker", frame);
//quit on ESC button
if (waitKey(1) == 27)break;
}
}
(2)、教学视频贾志刚改写的多目标跟踪算法****成功
//先框选目标,按空格或者ENTER键确认,依次选择,选择完成后按ESC键
#include
#include
#include
using namespace cv;
using namespace std;
inline cv::Ptr
{
cv::Ptr
if (name == "KCF")
tracker = cv::TrackerKCF::create();
else if (name == "TLD")
tracker = cv::TrackerTLD::create();
else if (name == "BOOSTING")
tracker = cv::TrackerBoosting::create();
else if (name == "MEDIAN_FLOW")
tracker = cv::TrackerMedianFlow::create();
else if (name == "MIL")
tracker = cv::TrackerMIL::create();
else if (name == "GOTURN")
tracker = cv::TrackerGOTURN::create();
else if (name == "MOSSE")
tracker = cv::TrackerMOSSE::create();
else if (name == "CSRT")
tracker = cv::TrackerCSRT::create();
else
CV_Error(cv::Error::StsBadArg, "Invalid tracking algorithm name\n");
return tracker;
}
int main(int agrc, char ** agrv)
{
//VideoCapture capture;
//capture.open("C:/Users/25503/Desktop/张教授项目/text.mp4");
VideoCapture capture(0);//打开摄像头
std::string trackingAlg = "MEDIAN_FLOW";//选择多目标算法,当前选用的是Median_Flow跟踪算法作为多目标跟踪算法
if (!capture.isOpened())
{
printf("could not load data....\n");
return -1;
}
//namedWindow("Multiple Objects Tracking-1", CV_WINDOW_AUTOSIZE);
MultiTracker trackers ;//定义多目标对象trackers
vector
Mat frame;
capture.read(frame);
selectROIs("Multiple Objects Tracking", frame, ROIs);//绘制选定目标
if (ROIs.size() < 1)
{
return -1;
}
std::vector
vector
for (size_t i = 0; i < ROIs.size(); i++)
{
algorithms.push_back(createTrackerByName(trackingAlg));//调用多目标算法函数,此时的trackingAlg代表多目标跟踪具体选用的跟踪算法
objects.push_back(ROIs[i]);
}
trackers.add(algorithms, frame, objects);
while (capture.read(frame))
{
trackers.update(frame);
for (size_t t = 0; t < trackers.getObjects().size(); t++)
{
rectangle(frame, trackers.getObjects()[t], Scalar(0, 0, 255), 2, 8, 0);
}
imshow("Multiple Objects Tracking", frame);
char c = waitKey(50);
if (c == 27)
{
break;
}
}
capture.release();
waitKey(0);
return -1;
}
P124 DNN模块概述2021/1/21--深度学习模块***
P125 -P126 GooleNet模型实现图像数据分类
(1)、CSDN读入图片的GOOLENet实现图像分类代码:成功
#include
#include
#include
using namespace cv;
using namespace std;
using namespace cv::dnn;
string caffe_model_file = "D:/OpenCV神经网络2/GooleNet模型分类/bvlc_googlenet.caffemodel"; //训练文件
string caffe_txt_file = "D:/OpenCV神经网络2/GooleNet模型分类/bvlc_googlenet.txt"; //描述文件
string labels_txt_file = "D:/OpenCV神经网络2/GooleNet模型分类/synset_words.txt"; //标签文件
vector
int main(int argc, char** argv)
{
Mat src = imread("C:/Users/25503/Desktop/123.png");
if (src.empty())
{
cout << "图片未找到!!!" << endl;
return -1;
}
//imshow("input image", src);
vector
Net caffe_net = readNetFromCaffe(caffe_txt_file, caffe_model_file);
if (caffe_net.empty())
{
return -1;
}
Mat inputblob = blobFromImage(src, 1.0, Size(224, 224), Scalar(104, 117, 123)); //将读进来的图像转为blob
Mat prob;
caffe_net.setInput(inputblob, "data");//第一层是data
prob = caffe_net.forward("prob");
Mat Matprob = prob.reshape(1, 1); //维度变成1*1000
double Probability; //最大相似度
Point classindex;
minMaxLoc(Matprob, NULL, &Probability, NULL, &classindex);
int Nameindex = classindex.x; //最大相似度对应的索引
cout << "Probability:" << Probability * 100 << "%" << endl;
cout << "NameValue:" << labels.at(Nameindex) << endl;
putText(src, labels.at(Nameindex), Point(20, 20), FONT_HERSHEY_SIMPLEX, 1.0, Scalar(0, 0, 255), 2, 8);
imshow("result image", src);
waitKey(0);
return 0;
}
vector
{
vector
ifstream fp(labels_txt_file);//读入文件
if (!fp.is_open())
{
cout << "文件未找到!!!" << endl;
exit(-1);
}
string name;
while (!fp.eof()) //当文件没有读到尾部
{
getline(fp, name); //读取文件每一行,从fp中读取,将结果放在name里面去
if (name.length())
{
classNames.push_back(name.substr(name.find(" ") + 1)); //从空格后面开始取字符
}
}
fp.close();//关闭输入输出流
return classNames;
}
(2)、CSDN读入视频/摄像头的GooleNet实现图像分类代码:成功
#include
#include
#include
using namespace cv;
using namespace std;
using namespace cv::dnn;
string caffe_model_file = "D:/OpenCV神经网络2/GooleNet模型分类/bvlc_googlenet.caffemodel"; //训练文件
string caffe_txt_file = "D:/OpenCV神经网络2/GooleNet模型分类/bvlc_googlenet.txt"; //描述文件
string labels_txt_file = "D:/OpenCV神经网络2/GooleNet模型分类/synset_words.txt"; //标签文件
vector
int main(int argc, char** argv)
{
Mat frame;
VideoCapture capture(0);//打开摄像头
//Mat src = imread("D:/test/cat.jpg");
if (!capture.isOpened())
{
cout << "摄像头未找到!!!" << endl;
return -1;
}
//imshow("input image", src);
vector
Net caffe_net = readNetFromCaffe(caffe_txt_file, caffe_model_file);
if (caffe_net.empty())
{
return -1;
}
Mat inputblob;
Mat prob, Matprob;
double Probability; //最大相似度
Point classindex;
while (capture.read(frame))
{
inputblob = blobFromImage(frame, 1.0, Size(224, 224), Scalar(104, 117, 123)); //将读进来的图像转为blob
caffe_net.setInput(inputblob, "data");//第一层是data
prob = caffe_net.forward("prob");
Matprob = prob.reshape(1, 1); //维度变成1*1000
minMaxLoc(Matprob, NULL, &Probability, NULL, &classindex);
int Nameindex = classindex.x; //最大相似度对应的索引
cout << "Probability:" << Probability * 100 << "%" << endl;
cout << "NameValue:" << labels.at(Nameindex) << endl;
putText(frame, labels.at(Nameindex), Point(20, 20), FONT_HERSHEY_SIMPLEX, 1.0, Scalar(0, 0, 255), 2, 8);
imshow("result image", frame);
char c = waitKey(5);
if (c == 27)
{
break;
}
}
waitKey(0);
return 0;
}
vector
{
vector
ifstream fp(labels_txt_file);//读入文件
if (!fp.is_open())
{
cout << "文件未找到!!!" << endl;
exit(-1);
}
string name;
while (!fp.eof()) //当文件没有读到尾部
{
getline(fp, name); //读取文件每一行,从fp中读取,将结果放在name里面去
if (name.length())
{
classNames.push_back(name.substr(name.find(" ") + 1)); //从空格后面开始取字符
}
}
fp.close();//关闭输入输出流
return classNames;
}
(3)、教学视频读入图片的GooleNet实现图像分类代码:成功
#include
#include
#include
using namespace cv;
using namespace cv::dnn;
using namespace std;
String model_bin_file = "D:/OpenCV神经网络2/GooleNet模型分类/bvlc_googlenet.caffemodel";//训练文件
String model_txt_file = "D:/OpenCV神经网络2/GooleNet模型分类/bvlc_googlenet.txt";//描述文件
String labels_txt_file = "D:/OpenCV神经网络2/GooleNet模型分类/synset_words.txt";//标签文件
vector
int main(int agrc, char** agrv)
{
Mat src = imread("C:/Users/25503/Desktop/12345.jpg");//读入图片
if (src.empty())
{
printf("could not load image...\n");
return -1;
}
namedWindow("input image", CV_WINDOW_AUTOSIZE);
imshow("input image", src);
vector
Net net = readNetFromCaffe(model_txt_file, model_bin_file);//神经网络函数调用
if (net.empty())
{
printf("read caffe model data failure...\n");
return -1;
}
Mat inputBlob = blobFromImage(src, 1.0, Size(224, 224), Scalar(104, 117, 123));
Mat prob;
for (int i = 0; i < 10; i++)
{
net.setInput(inputBlob, "data");
prob = net.forward("prob");
}
Mat probMat = prob.reshape(1, 1);
Point classNumber;
double classProb;
minMaxLoc(probMat, NULL, &classProb, NULL, &classNumber);
int classidx = classNumber.x;
printf("\n current image classification :%s, possible :%.2f", labels.at(classidx).c_str(), classProb);
//putText(src, labels.at(classidx), Point(20, 20), FONT_HERSHEY_PLAIN, 1.0, Scalar(0, 0, 255), 2, 8);//在读取的图片标记神经网络分类后的字体
putText(src, labels.at(classidx), Point(20, 20), FONT_HERSHEY_SIMPLEX, 1.0, Scalar(0, 0, 255), 2, 8);
imshow("Image Classification", src);
waitKey(0);
return 0;
}
vector
{
vector
ifstream fp(labels_txt_file);
if (!fp.is_open())
{
printf("could not open the file");
exit(-1);
}
string name;
while (!fp.eof())
{
getline(fp, name);
if (name.length())
{
classNames.push_back(name.substr(name.find(' ') + 1));//按照标签文件处理图片
}
}
fp.close();
return classNames;
}
P127-P128 深度神经网络SSD模型实现图像检测*****成功
(1)CSDN 上的SSD神经网络代码:成功,但需要训练标签文件
#include
#include
#include
using namespace cv;
using namespace std;
using namespace cv::dnn;
const size_t width = 300;
const size_t height = 300;//定义图像文件宽高
vector
string label_file = "D:/OpenCV神经网络2/SSD神经网络/labelmap_det.txt";//标签文件
string deploy_file = "D:/OpenCV神经网络2/SSD神经网络/deploy.txt";//描述文件
string model_file = "D:/OpenCV神经网络2/SSD神经网络/VGG_ILSVRC2016_SSD_300x300_iter_440000.caffemodel";
int main(int argc, char **argv)
{
Mat src = imread("C:/Users/25503/Desktop/12345.jpg");
if (src.empty())
{
cout << "图像未找到!!!" << endl;
return -1;
}
vector
namedWindow("input image", WINDOW_AUTOSIZE);
imshow("input image", src);
Net net = readNetFromCaffe(deploy_file, model_file);
Mat frame;
src.copyTo(frame);
if (frame.channels() == 4)
{
cvtColor(frame, frame, COLOR_BGRA2BGR);//将4通道转为3通道
}
if (frame.channels() == 1)
{
cvtColor(frame, frame, COLOR_GRAY2BGR);//将单通道转为3通道
}
Mat blob_Img = blobFromImage(frame, 1.0f, Size(width, height), Scalar(104, 117, 123), false, false);
net.setInput(blob_Img, "data");//开始层
Mat detection = net.forward("detection_out");//最后一层
Mat detectionMat(detection.size[2], detection.size[3], CV_32F, detection.ptr
/*
detection.size[2]表示宽度
detection.size[3]表示高度
*/
float confidence_threshold = 0.2;
for (int i = 0; i < detectionMat.rows; i++)
{
float confidence = detectionMat.at
if (confidence > confidence_threshold) {
size_t objIndex = (size_t)(detectionMat.at
float tl_x = detectionMat.at
float tl_y = detectionMat.at
float br_x = detectionMat.at
float br_y = detectionMat.at
Rect object_box((int)tl_x, (int)tl_y, (int)(br_x - tl_x), (int)(br_y - tl_y));
rectangle(frame, object_box, Scalar(0, 0, 255), 2, 8, 0);
putText(frame, format("%s", objnames[objIndex].c_str()), Point(tl_x + 1, tl_y + 1), FONT_HERSHEY_PLAIN, 2.0, Scalar(255, 0, 0), 2);
//cout << objIndex << endl;
}
}
imshow("output image", frame);
waitKey(0);
return 0;
}
vector
{
vector
ifstream fp(label_file);//打开输入流,读入文件
if (!fp.is_open())
{
printf("文件读入失败!!!\n");
exit(-1);//直接退出
}
string name;//标签文件中都有对应的名字
while (!fp.eof())//当文件没有读到结尾
{
getline(fp, name);//读取每一行
if (name.length())
{
string temp1 = name.substr(name.find(",") + 1); //找到每行第一个逗号,从逗号后面开始取数据
string temp2 = temp1.substr(temp1.find(",") + 1);//找到新的(第二个)逗号,从逗号后面开始取数据
objNames.push_back(temp2);
}
}
/*for (vector
{
//输出*iter才是输出那些字符串
cout << *iter << endl;
}*/
return objNames;
}
(2)教学视频上的SSD对象检测代码:失败,可能因为Caffe模型找的不正确
#include
#include
#include
using namespace cv;
using namespace std;
using namespace cv::dnn;
const size_t width = 300;
const size_t height = 300;
String labelFile = "D:/OpenCV神经网络2/SSD神经网络/labelmap_det.txt";//标签文件
String modelFile = "D:/OpenCV神经网络2/SSD神经网络/VGG_ILSVRC2016_SSD_300x300_iter_440000.caffemodel";//模型文件
String model_text_file = "D:/OpenCV神经网络2/SSD神经网络/deploy.txt";//描述文件
vector
const int meanValues[3] = { 104,117,123 };
static Mat getMean(const size_t &w, const size_t &h)
{
Mat mean;
vector
for (int i = 0; i < 3; i++)
{
Mat channel(h, w, CV_32F, Scalar(meanValues[i]));
channels.push_back(channel);
}
merge(channels, mean);
return mean;
}
static Mat preprocess(const Mat &frame)
{
Mat preprocessed;
frame.convertTo(preprocessed, CV_32F);
resize(preprocessed, preprocessed, Size(width, height));//300x300 image
Mat mean = getMean(width, height);
subtract(preprocessed, mean, preprocessed);
return preprocessed;
}
int main(int agrc, char** agrv)
{
Mat src = imread("C:/Users/25503/Desktop/12345.jpg");
if (src.empty())
{
printf("could not load image...\n");
return -1;
}
namedWindow("input image", CV_WINDOW_AUTOSIZE);
imshow("input image", src);
vector
//import Caffe SSD model
Net net = readNetFromCaffe(model_text_file, modelFile);
Mat frame;
src.copyTo(frame);
if (frame.channels() == 4)
{
cvtColor(frame, frame, COLOR_BGRA2BGR);//将4通道转为3通道
}
if (frame.channels() == 1)
{
cvtColor(frame, frame, COLOR_GRAY2BGR);//将单通道转为3通道
}
Mat input_imahe = preprocess(frame);
Mat bloImage = blobFromImage(input_imahe);
net.setInput(bloImage,"data");
Mat detection = net.forward("detection_out");
Mat detectionMat(detection.size[2], detection.size[3], CV_32F, detection.ptr
float confidence_threshold = 0.1;
//float confidence_threshold = 0.2;
for (int i = 0; i < detectionMat.rows; i++)
{
float confidence = detectionMat.at
if (confidence > confidence_threshold)
{
size_t objIndex = (size_t)(detectionMat.at
float t1_x = detectionMat.at
float t1_y = detectionMat.at
float br_x = detectionMat.at
float br_y = detectionMat.at
Rect object_box((int)t1_x, (int)t1_y, (int)(br_x - t1_x), (int)(br_y - t1_y));
rectangle(frame, object_box, Scalar(0, 0, 255), 2, 8, 0);
putText(frame, format("%s",objNames[objIndex].c_str()), Point(t1_x, t1_y), FONT_HERSHEY_SIMPLEX, 1.0, Scalar(255, 0, 0), 2);
}
}
imshow("ssd-demo", frame);
waitKey(0);
return 0;
}
vector
{
vector
ifstream fp(labelFile);
if (!fp.is_open())
{
printf("could not open the file...\n");
exit(-1);
}
string name;
while (!fp.eof())
{
getline(fp, name);
if (name.length() && (name.find("display_name:") == 0))
{
string temp = name.substr(15);
temp.replace(temp.end() - 1, temp.end(), "");
objNames.push_back(temp);
}
}
return objNames;
}
P129 MobileNet-SSD深度神经网络对象检测*****成功,极好
(1)、CSDN上的MobileNet-SSD目标对象检测(注意:MobileNet-SSD可以检测到具体到需要的对象,而单纯SSD只要在标签对象里面都能检测出来,根据实际需要选择检测方法)
#include
#include
#include
using namespace cv;
using namespace cv::dnn;
using namespace std;
const size_t width = 300;
const size_t height = 300;
const float meanVal = 127.5;//均值
const float scaleFactor = 0.007843f;
const char* classNames[] = { "background",
"aeroplane", "bicycle", "bird", "boat",
"bottle", "bus", "car", "cat", "chair",
"cow", "diningtable", "dog", "horse",
"motorbike", "person", "pottedplant",
"sheep", "sofa", "train", "tvmonitor" };
//模型文件
String modelFile = "D:/OpenCV神经网络2/SSDMoblieNet神经网络/MobileNetSSD_deploy.caffemodel";
//二进制描述文件
String model_text_file = "D:/OpenCV神经网络2/SSDMoblieNet神经网络/MobileNetSSD_deploy.txt";
int main(int argc, char** argv) {
VideoCapture capture;//读取视频
capture.open(0);
namedWindow("input", CV_WINDOW_AUTOSIZE);
int w = capture.get(CAP_PROP_FRAME_WIDTH);//获取视频宽度
int h = capture.get(CAP_PROP_FRAME_HEIGHT);//获取视频高度
printf("frame width : %d, frame height : %d", w, h);
// set up net
Net net = readNetFromCaffe(model_text_file, modelFile);
Mat frame;
while (capture.read(frame)) {
imshow("input", frame);
// 预测
Mat inputblob = blobFromImage(frame, scaleFactor, Size(width, height), meanVal, false);
net.setInput(inputblob, "data");
Mat detection = net.forward("detection_out");
// 绘制
Mat detectionMat(detection.size[2], detection.size[3], CV_32F, detection.ptr
float confidence_threshold = 0.25;//自信区间,越小检测到的物体越多(>=0.25)
for (int i = 0; i < detectionMat.rows; i++) {
float confidence = detectionMat.at
if (confidence > confidence_threshold) {
size_t objIndex = (size_t)(detectionMat.at
float tl_x = detectionMat.at
float tl_y = detectionMat.at
float br_x = detectionMat.at
float br_y = detectionMat.at
Rect object_box((int)tl_x, (int)tl_y, (int)(br_x - tl_x), (int)(br_y - tl_y));
rectangle(frame, object_box, Scalar(0, 0, 255), 2, 8, 0);
putText(frame, format("%s", classNames[objIndex]), Point(tl_x, tl_y), FONT_HERSHEY_SIMPLEX, 1.0, Scalar(255, 0, 0), 2);
}
}
imshow("ssd-video-demo", frame);
char c = waitKey(5);
if (c == 27) { // 如果ESC按下
break;
}
}
capture.release();
waitKey(0);
return 0;
}
(2)、教学视频上的MobileNet-SSD目标对象检测代码:效果极好
#include
#include
#include
using namespace cv;
using namespace cv::dnn;
using namespace std;
const size_t width = 300;
const size_t height = 300;
const float meanVal = 127.5;
const float scaleFactor = 0.007843f;
const char* classNames[] = { "background",
"aeroplane","bicycle","bird","boat",
"bottle","bus","car","cat","chair",
"cow","diningtable","dog","horse",
"motorbike","person","pottedplant",
"sheep","sofa","train","tvmonitor"
};
String modelFile = "D:/OpenCV神经网络2/SSDMoblieNet神经网络/MobileNetSSD_deploy.caffemodel";
String model_text_file = "D:/OpenCV神经网络2/SSDMoblieNet神经网络/MobileNetSSD_deploy.txt";
int main(int agrc, char** agrv)
{
VideoCapture capture(0);
namedWindow("input", CV_WINDOW_AUTOSIZE);
int w = capture.get(CAP_PROP_FRAME_WIDTH);
int h = capture.get(CAP_PROP_FRAME_HEIGHT);
printf("frame width :%d,frame height :%d", w, h);
//set up net
Net net = readNetFromCaffe(model_text_file, modelFile);
Mat frame;
while (capture.read(frame))
{
imshow("input", frame);
//预测
Mat inputblob = blobFromImage(frame, scaleFactor, Size(width, height), meanVal, false);
net.setInput(inputblob, "data");
Mat detection = net.forward("detection_out");
//绘制
Mat detectionMat(detection.size[2], detection.size[3], CV_32F, detection.ptr
float confidence_threshold = 0.2;
//float confidence_threshold = 0.25;
//float confidence_threshold = 0.5;
for (int i = 0; i < detectionMat.rows; i++)
{
float confidence = detectionMat.at
if (confidence > confidence_threshold)
{
size_t objIndex = (size_t)(detectionMat.at
float t1_x = detectionMat.at
float t1_y = detectionMat.at
float br_x = detectionMat.at
float br_y = detectionMat.at
Rect object_box((int)t1_x, (int)t1_y, (int)(br_x - t1_x), (int)(br_y - t1_y));
rectangle(frame, object_box, Scalar(0, 0, 255), 2, 8, 0);
putText(frame, format("%s", classNames[objIndex]), Point(t1_x, t1_y), FONT_HERSHEY_SIMPLEX, 1.0, Scalar(255, 0, 0), 2);
}
}
imshow("ssd-video-demo", frame);
char c = waitKey(50);
if (c == 27)//按下ESC键
{
break;
}
}
capture.release();
waitKey(0);
return 0;
}
P130-P131 FCN全卷积神经网络图像分割
(1) CSDN FCN全卷积神经网络图像分割代码:成功,效果极好***
#include
#include
#include
using namespace cv;
using namespace cv::dnn;
using namespace std;
const size_t width = 300;
const size_t height = 300;
String labelFile = "D:/OpenCV神经网络2/FCN全卷积神经网络图像分割/pascal-classes.txt";
String modelFile = "D:/OpenCV神经网络2/FCN全卷积神经网络图像分割/fcn8s-heavy-pascal.caffemodel";
String model_text_file = "D:/OpenCV神经网络2/FCN全卷积神经网络图像分割/fcn8s-heavy-pascal.txt";
vector
int main(int argc, char** argv) {
Mat frame = imread("C:/Users/25503/Desktop/9999.jpg");
if (frame.empty()) {
printf("could not load image...\n");
return -1;
}
namedWindow("input image", CV_WINDOW_AUTOSIZE);
imshow("input image", frame);
resize(frame, frame, Size(500, 500));//改变尺寸
vector
//
// init net 初始化网络
Net net = readNetFromCaffe(model_text_file, modelFile);
Mat blobImage = blobFromImage(frame);
// use net 使用网络
float time = getTickCount();
net.setInput(blobImage, "data");
Mat score = net.forward("score");
float tt = getTickCount() - time;
printf("time consume: %.2f ms \n", (tt / getTickFrequency()) * 1000);
// segmentation and display 分割并显示
const int rows = score.size[2];
const int cols = score.size[3];
const int chns = score.size[1];
Mat maxCl(rows, cols, CV_8UC1);
Mat maxVal(rows, cols, CV_32FC1);
// setup LUT LUT查找
for (int c = 0; c < chns; c++) {
for (int row = 0; row < rows; row++) {
const float *ptrScore = score.ptr
uchar *ptrMaxCl = maxCl.ptr
float *ptrMaxVal = maxVal.ptr
for (int col = 0; col < cols; col++) {
if (ptrScore[col] > ptrMaxVal[col]) {
ptrMaxVal[col] = ptrScore[col];
ptrMaxCl[col] = (uchar)c;
}
}
}
}
// look up colors 找到对应颜色
Mat result = Mat::zeros(rows, cols, CV_8UC3);
for (int row = 0; row < rows; row++) {
const uchar *ptrMaxCl = maxCl.ptr
Vec3b *ptrColor = result.ptr
for (int col = 0; col < cols; col++) {
ptrColor[col] = colors[ptrMaxCl[col]];
}
}
Mat dst;
imshow("FCN-demo1", result);
addWeighted(frame, 0.3, result, 0.7, 0, dst);//增加宽度
imshow("FCN-demo", dst);
waitKey(0);
return 0;
}
vector
vector
ifstream fp(labelFile);
if (!fp.is_open()) {
printf("could not open the file...\n");
exit(-1);
}
string line;
while (!fp.eof()) {
getline(fp, line);
if (line.length()) {
stringstream ss(line);
string name;
ss >> name;
int temp;
Vec3b color;
ss >> temp;
color[0] = (uchar)temp;
ss >> temp;
color[1] = (uchar)temp;
ss >> temp;
color[2] = (uchar)temp;
colors.push_back(color);
}
}
return colors;
}
(2) 教学视频上的 FCN全卷积神经网络图像分割代码:图像分割效果极好*****
#include
#include
#include
using namespace cv;
using namespace std;
using namespace cv::dnn;
const size_t width = 500;
const size_t height = 500;//定义图像文件宽高
vector
string label_file = "D:/OpenCV神经网络2/FCN全卷积神经网络图像分割/pascal-classes.txt";
string deploy_file = "D:/OpenCV神经网络2/FCN全卷积神经网络图像分割/fcn8s-heavy-pascal.txt";
string model_file = "D:/OpenCV神经网络2/FCN全卷积神经网络图像分割/fcn8s-heavy-pascal.caffemodel";
int main(int argc, char **argv)
{
Mat src = imread("C:/Users/25503/Desktop/9999.jpg");
if (!src.data)
{
cout << "图像文件未找到!!!" << endl;
return -1;
}
resize(src, src, Size(500, 500), 0, 0);
vector
Net net;
net = readNetFromCaffe(deploy_file, model_file);//读取二进制文件和描述文件
float t1 = getTickCount();
Mat inputblob = blobFromImage(src);
net.setInput(inputblob, "data");
Mat score = net.forward("score");
float t2 = getTickCount();
float t = (t2 - t1) / getTickFrequency();
cout << "运行时间:" << t << endl;
const int rows = score.size[2]; //图像的高
const int cols = score.size[3]; //图像的宽
const int chns = score.size[1]; //图像的通道数
Mat maxCl(rows, cols, CV_8UC1);
Mat maxVal(rows, cols, CV_32FC1);
for (int c = 0; c < chns; c++) {
for (int row = 0; row < rows; row++) {
const float *ptrScore = score.ptr
uchar *ptrMaxCl = maxCl.ptr
float *ptrMaxVal = maxVal.ptr
for (int col = 0; col < cols; col++) {
if (ptrScore[col] > ptrMaxVal[col]) {
ptrMaxVal[col] = ptrScore[col];
ptrMaxCl[col] = (uchar)c;
}
}
}
}
// look up colors
Mat result = Mat::zeros(rows, cols, CV_8UC3);
for (int row = 0; row < rows; row++) {
const uchar *ptrMaxCl = maxCl.ptr
Vec3b *ptrColor = result.ptr
for (int col = 0; col < cols; col++) {
ptrColor[col] = colors[ptrMaxCl[col]];
}
}
Mat dst;
addWeighted(src, 0.3, result, 0.7, 0, dst); //图像合并
imshow("FCN-demo", dst);
waitKey(0);
destroyAllWindows();
return 0;
}
vector
{
vector
ifstream fp(label_file);//打开输入流,读入文件
if (!fp.is_open())
{
printf("文件读入失败!!!\n");
exit(-1);//直接退出
}
string names;
int temp;
Vec3b color;
string line;//标签文件中都有对应的名字
while (!fp.eof())//当文件没有读到结尾
{
getline(fp, line);//读取每一行
stringstream ss(line); //分割字符串
ss >> names; //读的第一个字符串是names
ss >> temp;
color[0] = temp; //读一个字符串就给color
ss >> temp;
color[1] = temp;
ss >> temp;
color[2] = temp;
colors.push_back(color);
}
return colors;
}