#include "quickdemo.h"
using namespace cv;
using namespace std;
using namespace dnn;
#include
#include
QuickDemo::QuickDemo()
{
}
void QuickDemo::colorSpace_Demo(Mat &change){
Mat one,two;
cvtColor(change,one,COLOR_BGR2HSV);//转成hsv
cvtColor(change,two,COLOR_BGR2GRAY);//转成hsv
imshow("hsv",one);
imshow("黑白",two);
imwrite("E:\\BaiduNetdiskDownload\\hsv.jpg",one);
imwrite("E:\\BaiduNetdiskDownload\\heibai.jpg",two);
}
void QuickDemo::mat_creation_demo(cv::Mat &change){//di3节//创建的时候宽高,高row=行
Mat m1,m2;//克隆和拷贝都是值拷贝,赋值=是指向同一份数据,类似于指针
m1.copyTo(change);
m2=change.clone();//克隆
//创建空白图像
Mat m3=Mat::zeros(Size(5,4),CV_8UC3);//8位得无符号int单通道,最后数字表示几通道,值全是0
// Mat m3=Mat::ones(Size(3,8),CV_8UC1);//使用ones创建空白图像得时候单通道全是1,多通道只有第一个通道是1
//给像素点通道赋值
// m3=255;//给单通道赋值
m3=Scalar(88,66,77);//给多通道赋值
cout <<"宽度"<(3,3)<<1,5,6,8,7,9,9,8,7);//默认通道数1
}
void QuickDemo::xiangshuduxie_demo(cv::Mat &change){//像素读写操作//高行
int tongdao=change.channels();
int hang=change.rows;
int lie=change.cols;
for (int row=0;row(row,col);
change.at(row,col)=255-xiangsudian;
}
if (tongdao==3) {
Vec3b xiangsudian=change.at(row,col); //Vec3b相当于一个存放3个uchar类型得数组,int类型Vec3i,浮点类型Vec3f
change.at(row,col)[0]=255-xiangsudian[0];
change.at(row,col)[1]=255-xiangsudian[1];
change.at(row,col)[2]=255-xiangsudian[2];
}
}
}
// for (int row=0;row(row);//将第一行赋给指针,数组赋给指针,指针指向数组首地址,也就是该行第一个像素点
// for (int col=0;col,当使用它时会保证BGR图像的像素值在[0,255] saturate_cast(p1[0]+p2[0]),可以是别的符号,可以保证数值在有效范围内
// Mat ceshi=change+Scalar(50,50,50);
// add(change,Scalar(50,50,50),ceshi); //多种用法,最好用函数,加标准定义,如下
Mat scr=Mat::zeros(change.size(),change.type());
Mat zhongjian=Mat::zeros(change.size(),change.type());
zhongjian=Scalar(50,50,50);
// add(change,zhongjian,scr);//加法
// subtract(change,zhongjian,scr);//减法
// multiply(change,zhongjian,scr);//乘法
divide(change,zhongjian,scr);//除法
namedWindow("结果",WINDOW_FREERATIO);
imshow("结果",scr);
}
//void on_treak(int chushzhi,void *p){/*传统版本亮度*/
// Mat src=*((Mat*)p);
// Mat zhongjian=Mat::zeros(src.size(),src.type());
// Mat jieguo=Mat::zeros(src.size(),src.type());
// zhongjian=Scalar(chushzhi,chushzhi,chushzhi);
// add(src,zhongjian,jieguo);
// imshow("亮度和对比度窗口",jieguo);
//}
void on_treak(int chushzhi,void *p){/*ddWeighted版本亮度*/
Mat src=*((Mat*)p);
Mat zhongjian=Mat::zeros(src.size(),src.type());
Mat jieguo=Mat::zeros(src.size(),src.type());
double fanwei=chushzhi-50;
addWeighted(src,1,zhongjian,0,fanwei,jieguo);
imshow("亮度和对比度窗口",jieguo);
}
void duibidu(int chushzhi,void *p){
// addWeighted
// 共7个参数
// 第1个参数 第一个输入 src1
// 第2个参数 第一个输入的权重 alpha
// 第3个参数 第二个输入 src2
// 第4个参数 第二个输入的权重 beta
// 第5个参数 每个数要增加的标量 gamma
// 第6个参数 输出 dst图片
// 第7个参数 输出的可选深度(一般用不到)
// 公式
// dst = src1 * alpha + src2 * beta + gamma
// 范围截断在[0,255]
Mat src=*((Mat*)p);
Mat zhongjian=Mat::zeros(src.size(),src.type());
Mat jieguo=Mat::zeros(src.size(),src.type());
double quanzhong=chushzhi/100.0;
addWeighted(src,quanzhong,zhongjian,0,0,jieguo);
imshow("亮度和对比度窗口",jieguo);
}
void QuickDemo::gundongtiaoliangdu_demo(cv::Mat &change){
Mat src=change;
namedWindow("亮度和对比度窗口",WINDOW_FREERATIO);
int maxliangdu=100;
int l_chushzhi=50;
int maxduibidu=200;
int d_chushzhi=50;
createTrackbar("亮度:","亮度和对比度窗口",&l_chushzhi,maxliangdu,on_treak,(void*)&change);
createTrackbar("对比度:","亮度和对比度窗口",&d_chushzhi,maxduibidu,duibidu,(void*)&change);
}
void QuickDemo::jianpanshijian(cv::Mat &change){
Mat src=Mat::zeros(change.size(),change.type());
namedWindow("结果窗口",WINDOW_FREERATIO);
while (true)
{
int c=waitKey(1000);
if (c==27) {
break;
}else if (c==49)
{
cvtColor(change,src,COLOR_BGR2GRAY);
imshow("结果窗口",src);
}else if (c==50)
{
cvtColor(change,src,COLOR_BGR2HSV);
imshow("结果窗口",src);
}else if (c==51)
{
src=change+Scalar(50,50,50);
imshow("结果窗口",src);
}
}
}
void QuickDemo::zidaiyansebiao(cv::Mat &change){
int colormap[] = {
COLORMAP_AUTUMN,
COLORMAP_BONE,
COLORMAP_JET,
COLORMAP_WINTER,
COLORMAP_RAINBOW,
COLORMAP_OCEAN,
COLORMAP_SUMMER,
COLORMAP_SPRING,
COLORMAP_COOL,
COLORMAP_HSV,//10
COLORMAP_PINK,
COLORMAP_HOT,
COLORMAP_PARULA,
COLORMAP_MAGMA,
COLORMAP_INFERNO,
COLORMAP_PLASMA,
COLORMAP_VIRIDIS,
COLORMAP_CIVIDIS,
COLORMAP_TWILIGHT,
COLORMAP_TWILIGHT_SHIFTED,//20
COLORMAP_TURBO,
COLORMAP_DEEPGREEN
};
Mat src=Mat::zeros(change.size(),change.type());
int index{};
namedWindow("结果窗口",WINDOW_FREERATIO);
while (true) {
int c=waitKey(1000);
if (c==27) {
break;
}
applyColorMap(change,src,colormap[index%22]);
++index;
imshow("结果窗口",src);
}
}
void QuickDemo::luojiweiyunsun(cv::Mat &change){
// rectangele
// 绘制矩形
// 共7个参数
// 第1个参数 输入
// 第2个参数 矩形左上坐标
// 第3个参数 矩形右下坐标
// 第4个参数 矩形颜色
// 第5个参数 线宽
// 如果参数 >=0,则表示绘制矩形(如为1,表示绘制的矩形边为1个像素)
// 如果参数 < 0,则表示填充矩形(如-1,表示填充整个矩形)
// 第6个参数 lineType
// 关于图像锯齿,有几种方式处理
// 不管不顾,就用LINE_4 或者 LINE_8
// 消除锯齿,就用LINE_AA (AA就是反锯齿)
// 第7个参数 缩小图像,同时缩短矩形左上顶点与(0,0)位置的距离
// 0表示不变
// 1表示图像*1/2,同时距离(0,0)的x方向和y方向距离*1/2
// 2表示图像*(1/2)^2,同时距离(0,0)的x方向和y方向距离*(1/2)^2
Mat m1=Mat::zeros(Size(250,250),CV_8UC3);
Mat m2=Mat::zeros(Size(250,250),CV_8UC3);
rectangle(m1,Point(120,200),Point(150,250),Scalar(3,88,99),-1,LINE_8,0);
rectangle(m2,Rect(88,120,130,140),Scalar(35,88,250),-1,LINE_8,0);//用左上角下标,后面两个是矩形大小Rect
imshow("m1",m1);
imshow("m2",m2);
Mat m4;
// bitwise_and(m1,m2,m4);//交及
// bitwise_or(m1,m2,m4);//并及
// bitwise_not(change,m4);//取反相当于255减每个像素点
bitwise_xor(m1,m2,m4);//异或
imshow("m4",m4);
}
void QuickDemo::tongdaofenoli(cv::Mat &change){
vector tuxiang;
split(change,tuxiang);//通道分离
// imshow("蓝色",tuxiang[0]);
// imshow("绿色",tuxiang[1]);
// imshow("红色",tuxiang[2]);
Mat jieguo=Mat::zeros(change.size(),change.type());//使用mixChannels得时候得初始化
// tuxiang[0]=0;
// tuxiang[2]=0;//可以得到单一一种彩色得图像,合并起来后
merge(tuxiang,jieguo);//合并
// imshow("结果",jieguo);
// mixChannels
// 混合通道
// 共6个参数
// 第1个参数 输入
// 第2个参数 输入的矩阵数
// 第3个参数 输出
// 第4个参数 输出的矩阵数
// 第5个参数 从哪个通道 变成 哪个通道
// 第6个参数 要变的对数
// 这个混合的意思是,彩色图像本来是bgr的顺序,经过通道混合就变成了rgb。
int jiaohuan[]={0,2,1,2,2,0};
mixChannels(&change,1,&jieguo,1,jiaohuan,3);//混合,也可以把个4通道分为一个三通道和一个一同道,输出改成一个数组,数量改成2,对数改一下就可以了
imshow("结果",jieguo);
}
void QuickDemo::genhuanbeijing(cv::Mat &change){
// 在opencv中,我们提取指定色彩范围的区域,采用inRange实现,这样的一块区域,学名叫做ROI(region of interest),感兴趣区域。
// 关于inRange的提取原理
// 图像中,对于在指定色彩范围内的颜色,将置为255(白色),不在的则置为0(黑色)
// 对于多通道的输入,输出结果是各个通道的结果相与,当各通道结果都在上下限之内时,输出为255,否则为0。
// 因此也有人将输出理解为mask掩码模板,作为mask使用。inRange
// 提取指定色彩范围内的区域
// 共4个参数
// 第1个参数 输入
// 第2个参数 色彩下界
// 第3个参数 色彩上界
// 第4个参数 输出
Mat src;
cvtColor(change,src,COLOR_BGR2HSV);
inRange(src,Scalar(35,43,46),Scalar(77,255,255),src);
Mat beijing=Mat::zeros(change.size(),change.type());
beijing=Scalar(20,20,200);
bitwise_not(src,src);
imshow("inRange",src);
change.copyTo(beijing,src);//将src中不为0得像素点扣过来beijing里,再把change中赋值到src扣过来得部分,其余beijing不变
imshow("jieguo",beijing);
}
void QuickDemo::daxiaopingjun(cv::Mat &change){
// minMaxLoc
// 求取单通道图像像素的最小值,最大值
// 共6个参数
// 第1个参数 输入单通道图像
// 第2个参数 输出最小值
// 第3个参数 输出最大值
// 第4个参数 输出最小值点的坐标
// 第5个参数 输出最大值点的坐标
// 第6个参数 输入图像的子数组(有时候我们会求取ROI区域的最小/最大值,就会传入mask图像)
// (这里的子数组,是一种图像掩模,可以实现加东西/扣东西)
// meanStdDev
// 求取平均值,标准差
// 共4个参数
// 第1个参数 输入
// 第2个参数 输出图像像素的平均值,每个通道都会输出一个
// 第3个参数 输出图像像素的标准差,每个通道都会输出一个
// 第4个参数 输入图像的子数组(有时候我们会求取ROI区域的平均值/标准差,就会传入mask图像)
// (这里的子数组,是一种图像掩模,可以实现加东西/扣东西)
Point minp,maxp;
double min,max;
vector fenli;
split(change,fenli);
int i{1};
for(auto dantongdao:fenli){
minMaxLoc(dantongdao,&min,&max,&minp,&maxp);
cout <<"第"<=0)
// 第6个参数 lineType
// 第7个参数 缩短线段左上顶点与(0,0)位置的距离
// 0表示不变
// 1表示图像*1/2,同时距离(0,0)的x方向和y方向距离*1/2
// 2表示图像*(1/2)^2,同时距离(0,0)的x方向和y方向距离*(1/2)^2
// ellipse
// 绘制椭圆
// 共5个参数
// 第1个参数 输入
// 第2个参数 RotatedRect
// 第3个参数 椭圆颜色
// 第4个参数 线宽
// 第5个参数 lineType
Mat tuya=Mat::zeros(change.size(),change.type());
Rect rec;
rec.x=555;
rec.y=555;
rec.width=100;
rec.height=100;
rectangle(tuya,rec,Scalar(0,0,200),2,LINE_8,0);
//等价于rectangle(change,rec(55,55,100,100),Scalar(0,0,2000),2,LINE_8,0);
circle(tuya,Point(55,55),200,Scalar(255,200,200),2,LINE_AA,0);//圆形
line(tuya,Point(55,100),Point(105,100),Scalar(222,255,200),2,LINE_AA,0);
RotatedRect yuan;
yuan.center=Point(80,100);
yuan.size=Size(50,20);
yuan.angle=0;//旋转角度
ellipse(tuya,yuan,Scalar(22,25,20),2,LINE_AA);
addWeighted(change,0.7,tuya,0.5,0,tuya);
imshow("矩形",tuya);
}
void QuickDemo::suijishu(cv::Mat &change){
RNG rng(12345);
int w=change.cols;
int h=change.rows;
while (true) {
int c=waitKey(255);
if (c==27) {
break;
}
int x1=rng.uniform(0,w);
int x2=rng.uniform(0,w);
int y1=rng.uniform(0,h);
int y2=rng.uniform(0,h);
int b=rng.uniform(0,255);
int g=rng.uniform(0,255);
int r=rng.uniform(0,255);
line(change,Point(x1,y1),Point(x2,y2),Scalar(b,g,r),2,LINE_AA,0);
namedWindow("随机数",WINDOW_FREERATIO);
imshow("随机数",change);
}
}
void QuickDemo::duobianxinghuizhi(cv::Mat &change){
// polylines
// 绘制多条多边形曲线
// 共7个参数
// 第1个参数 输入
// 第2个参数 输入多边形点集(绘制边的顺序,与点集数组中点的顺序有关)
// 第3个参数 isclosed(bool类型)
// 第4个参数 多边形颜色
// 第5个参数 线宽
// 第6个参数 lineType
// 第7个参数 shift(左顶点缩小)
// fillPoly
// 填充绘制的多边形
// 共6个参数
// 第1个参数 输入
// 第2个参数 点集数组
// 第3个参数 填充颜色
// 第4个参数 lineType
// 第5个参数 shift
// 第6个参数 轮廓所有点的可选偏移
// drawContours
// 绘制轮廓轮廓/填充轮廓
// 共9个参数,这里我们只介绍前5个(剩下的有缺省值)
// 第1个参数 输入
// 第2个参数 多边形轮廓的数组
// 第3个参数 选择的多边形轮廓(在数组中的编号,-1为全选)
// 第4个参数 多边形颜色
// 第5个参数 填充/绘制(-1为填充)
Mat beijing=Mat::zeros(Size(500,500),CV_8UC3);
vectorduobianxing;
RNG rng(12345);
for (int i{};i<5;i++) {
int x=rng.uniform(0,500);
int y=rng.uniform(0,500);
duobianxing.push_back(Point(x,y));
}
// int b=rng.uniform(0,255);
// int g=rng.uniform(0,255);
// int r=rng.uniform(0,255);
/*polylines(beijing,duobianxing,true,Scalar(b,g,r),1,LINE_AA,0);
fillPoly(beijing,duobianxing,Scalar(rng.uniform(0,255),rng.uniform(0,255),rng.uniform(0,255)),LINE_AA,0);*///如果先填充再画线,就有边框
vector> jihe;
jihe.push_back(duobianxing);
drawContours(beijing,jihe,-1,Scalar(rng.uniform(0,255),rng.uniform(0,255),rng.uniform(0,255)),-1);//jihe是一个多边形得集合,这个函数可以同时画多个多边形
imshow("多边形",beijing);
}
Point s(0,0),e(0,0);Mat temp;
void shubiaohuidiao(int shijian,int x, int y,int jian,void* tupain){//jian这个参数用到得类型是按着不放那种,6种类型看官方文档,shijian类型是点击
// MouseCallback类型的函数(鼠标事件回调函数)
// 共5个参数,这5个参数全是针对鼠标的捕捉
// 第1个参数 捕捉的鼠标事件(查阅文档可知,都有什么类型)
// 第2个参数 捕捉的鼠标事件的x坐标
// 第3个参数 捕捉的鼠标事件的y坐标
// 第4个参数 标志捕捉的事件是哪一个键(有5种,查阅文档可知)
// 第5个参数 void*类型的可选传入数据
Mat src=*((Mat*)tupain);
if (shijian==EVENT_LBUTTONDOWN) {//按下左键
s.x=x;
s.y=y;
cout <<"起点"<(0,0));
double sin=abs(get.at(0,1));
int nw=w*cos+h*sin;
int nh=w*sin+h*cos;
get.at(0,2)+=(nw/2-w/2);//这里一定要这样字,不能直接赋值nw/2
get.at(1,2)+=(nh/2-h/2);
warpAffine(change,src,get,Size(nw,nh),INTER_NEAREST,0,Scalar(45,87,22));
namedWindow("旋转",WINDOW_FREERATIO);
imshow("旋转",src);
}
void QuickDemo::shipingcaozuo(cv::Mat &change){
VideoCapture video("E:\\BaiduNetdiskDownload\\opencv\\sources\\samples\\data\\Megamind.avi");
if (video.isOpened())
{
Mat tupian;
while (true) {
video.read(tupian);//读没了返回false并且传入空图像
if (tupian.empty()) {
break;
}
imshow("shiping",tupian);
if(waitKey(16)==27){
break;
}
}
}
video.release();
}
void QuickDemo::shipingshuxing(cv::Mat &change){
// VideoWriter (const String &filename, int fourcc, double fps, Size frameSize, bool isColor=true)
// 视频写入对象
// 共5个参数
// 第1个参数 视频文件路径
// 第2个参数 视频编码方式(我们可以通过VideoCapture::get(CAP_PROP_FOURCC)获得)
// 第3个参数 fps
// 第4个参数 size
// 第5个参数 是否为彩色
VideoCapture video("E:\\BaiduNetdiskDownload\\opencv\\sources\\samples\\data\\Megamind.avi");
int zhenkuandu=video.get(CAP_PROP_FRAME_WIDTH);
int zhengaodu=video.get(CAP_PROP_FRAME_HEIGHT);
int zongzhenshu=video.get(CAP_PROP_FRAME_COUNT);
int fps=video.get(CAP_PROP_FPS);
cout < fenli;
split(change,fenli);
const int channels[]={0};
int changdu[]={256};
const float fanwei[]={0,255};
Mat b_zft,g_zft,r_zft;
const float* fanweizongjie[]={fanwei};
calcHist(&fenli[0],1,channels,Mat(),b_zft,1,changdu,fanweizongjie);
calcHist(&fenli[1],1,channels,Mat(),g_zft,1,changdu,fanweizongjie);
calcHist(&fenli[2],1,channels,Mat(),r_zft,1,changdu,fanweizongjie);
int zftw=512;
int zfth=400;
int bin_w=cvRound((double)zftw/changdu[0]);//区间,两个点之间得距离横坐标
Mat xianshitu=Mat::zeros(Size(zftw,zfth),CV_8UC3);
normalize(b_zft,b_zft,0,xianshitu.rows,NORM_MINMAX,-1,Mat());
normalize(g_zft,g_zft,0,xianshitu.rows,NORM_MINMAX,-1,Mat());
normalize(r_zft,r_zft,0,xianshitu.rows,NORM_MINMAX,-1,Mat());
for (int i{};i<256;i++) {
Point p11(bin_w*i,zfth-cvRound(b_zft.at(i)));
Point p12(bin_w*i+bin_w,zfth-cvRound(b_zft.at(i+1)));
Point p21(bin_w*i,zfth-cvRound(g_zft.at(i)));
Point p22(bin_w*i+bin_w,zfth-cvRound(g_zft.at(i+1)));
Point p31(bin_w*i,zfth-cvRound(r_zft.at(i)));
Point p32(bin_w*i+bin_w,zfth-cvRound(r_zft.at(i+1)));
line(xianshitu,p11,p12,Scalar(255,0,0),1,LINE_AA,0);
line(xianshitu,p21,p22,Scalar(0,255,0),1,LINE_AA,0);
line(xianshitu,p31,p32,Scalar(0,0,255),1,LINE_AA,0);
}
imshow("直方图",xianshitu);
}
void QuickDemo::tupianzhifangtuerwei(cv::Mat &change){
Mat zhifangtu,hsv,jieguo;
cvtColor(change,hsv,COLOR_BGR2HSV);
int h_bin=30;
int s_bin=32;
int arr_bin[]={h_bin,s_bin};
float h_fanwei[]={0,180};//范围是float
float s_fanwei[]={0,255};
const float* range[]={h_fanwei,s_fanwei};//必须是const
int channels[]={0,1};
calcHist(&hsv,1,channels,Mat(),zhifangtu,2,arr_bin,range);
double max{};
minMaxLoc(zhifangtu,0,&max,0,0);
int diejialiang{10};
jieguo=Mat::zeros(Size(s_bin*diejialiang,h_bin*diejialiang),CV_8UC3);
for (int i=0;i(i,j);
int guiyizhi=cvRound(pingci/max*255);
Point p1(i*diejialiang,j*diejialiang);
Point p2((i+1)*diejialiang,(j+1)*diejialiang);
rectangle(jieguo,p1,p2,Scalar::all(guiyizhi),-1,LINE_AA);
}
}
applyColorMap(jieguo,jieguo,COLORMAP_DEEPGREEN);
imshow("zhifangtu",jieguo);
}
void QuickDemo::zhifangtujunheng(cv::Mat &change){
// equalizeHist
// 均衡灰度图像的直方图
// 共2个参数
// 第1个参数 输入
// 第2个参数 输出
// Mat huidu;
// cvtColor(change,huidu,COLOR_BGR2GRAY);
// Mat jieguo;
// equalizeHist(huidu,jieguo);
// imshow("huidu",huidu);
// imshow("jieguo",jieguo);//灰度图像均衡
//彩色图像均衡
Mat hsv,jieguo;
cvtColor(change,hsv,COLOR_BGR2HSV);
vector fenli;
split(hsv,fenli);
equalizeHist(fenli[2],fenli[2]);
merge(fenli,jieguo);
cvtColor(jieguo,jieguo,COLOR_HSV2BGR);
imshow("zftjh",jieguo);
}
void QuickDemo::tuxiangjuanji(cv::Mat &change){
// blur
// 使用归一化框滤镜模糊图像
// 共5个参数
// 第1个参数 输入
// 第2个参数 输出
// 第3个参数 卷积核size(卷积核越大,图像模糊程度越高)
// 第4个参数 锚点
// (默认值Point(-1,-1)表示锚点位于卷积后的内核中心,卷积后的值在这里更新)
// 第5个参数 图像边缘处理方式
// (默认参数 BORDER_DEFAULT 边缘有很多处理方式,查阅官方文档可知)
Mat jieguo;
blur(change,jieguo,Size(13,13));
// blur(change,jieguo,Size(1,13));//列卷积
// blur(change,jieguo,Size(13,1));//行卷积
imshow("jieguo",jieguo);
}
void QuickDemo::gaosimohu(cv::Mat &change){
// GaussianBlur
// 使用高斯滤镜模糊图像
// 共6个参数
// 第1个参数 输入
// 第2个参数 输出
// 第3个参数 高斯卷积核size(必须是整数和奇数,可以是0,然后根据sigma计算他们)
// 第4个参数 x方向的高斯核标准差
// 第5个参数 y方向的高斯核标准差(如果sigmaY = 0,则设置其 = sigmaX)
// (如果两个标准差都为0,则根据高斯卷积核size计算)
// (官方文档建议:三个参数最好都指定)
// 虽然size和sigma都可以实现模糊,但sigma的影响更大
// 第6个参数 图像边缘处理方式
Mat jieguo;
GaussianBlur(change,jieguo,Size(5,5),5,5);
imshow("jieguo",jieguo);
}
void QuickDemo::gaosimohushuangbian(cv::Mat &change){
// bilateralFilter 通常情况下sigmaColor取100 ~ 150,sigmaSpace取10 ~ 25
// 将双边过滤器应用于图像
// 共6个参数
// 第1个参数 输入
// 第2个参数 输出
// 第3个参数 过滤期间使用的每个像素邻域的直径(如为非正数,则根据sigmaSpac计算)一般为0
// 第4个参数 sigmaColor(在颜色空间中的过滤标准差)
// sigmaColor一般取值大一点,
// 大一点的话根据二维高斯函数计算所得的值越小,越趋近于0,影响越低
// 第5个参数 sigmaSpace(在坐标空间中的过滤标准差)
// 第6个参数 图像边缘处理方式
Mat jieguo;
bilateralFilter(change,jieguo,0,100,10);
// namedWindow("jieguo",WINDOW_FREERATIO);
imshow("jieguo",jieguo);
}
void QuickDemo::renlianshibie(cv::Mat &change){
string path="E:\\BaiduNetdiskDownload\\opencv\\sources\\samples\\dnn\\face_detector\\";
Net net=readNetFromTensorflow(path+"opencv_face_detector_uint8.pb",path+"opencv_face_detector.pbtxt");//读取模型进来
VideoCapture video("E:\\BaiduNetdiskDownload\\opencv\\sources\\samples\\data\\Megamind.avi");
Mat tupian;
if (video.isOpened())
{
while (true) {
video.read(tupian);
if (tupian.empty()) {
break;
}
Mat bandian=blobFromImage(tupian,1.0,Size(300, 300),Scalar(104, 177, 123),false,false);
net.setInput(bandian);
Mat huoqu=net.forward();
Mat dectectionMat(huoqu.size[2],huoqu.size[3],CV_32F,huoqu.ptr());
for (int i{0};i(i,2);
if (zhi>0.5) {
int x1=static_cast(dectectionMat.at(i,3)*tupian.cols);
int y1=static_cast(dectectionMat.at(i,4)*tupian.rows);
int x2=static_cast(dectectionMat.at(i,5)*tupian.cols);
int y2=static_cast(dectectionMat.at(i,6)*tupian.rows);
rectangle(tupian,Point(x1,y1),Point(x2,y2),Scalar(0,0,255),1,LINE_AA,0);
}
}
imshow("tup",tupian);
int c=waitKey(17);
if (c==27) {
break;
}
}
}
video.release();
}
void QuickDemo::wenzihuizhi(cv::Mat &change){
// putText
// 共9个参数
// 第1个参数 输入输出
// 第2个参数 字符串
// 第3个参数 字符串左下角的点
// 第4个参数 字体类型
// 第5个参数 字体大小
// 第6个参数 字体颜色
// 第7个参数 线宽
// 第8个参数 lineType
// 第9个参数 默认false,图像数据原点位于左上角
// 如果true,图像数据原点位于左下角
putText(change,"kkpp",Point(200,200),FONT_HERSHEY_COMPLEX,2.0,Scalar(45,18,77),2,LINE_AA);
namedWindow("jieguo",WINDOW_FREERATIO);
imshow("jieguo",change);
}
void QuickDemo::hezimohu(cv::Mat &change){
// boxfilter
// 使用方框滤镜模糊图像
// 共7个参数
// 第1个参数 输入
// 第2个参数 输出
// 第3个参数 输出图像深度(-1表示使用输入图像的深度)
// 第4个参数 ksize(模糊内核大小)
// 第5个参数 锚点(默认Point(-1,-1)表示锚点位于内核中心)
// 第6个参数 是否归一化(默认为true)
// 第7个参数 borderType
Mat jieguo;
boxFilter(change,jieguo,-1,Size(30,30));//Size越大越模糊
namedWindow("jieguo",WINDOW_FREERATIO);
imshow("jieguo",jieguo);
}
void QuickDemo::zidingyilvbo(cv::Mat &change){
// filter2D
// 将图像与内核卷积
// 共7个参数
// 第1个参数 输入
// 第2个参数 输出
// 第3个参数 输出图像的深度(-1表示和输入图像一直)
// 第4个参数 卷积核
// 第5个参数 锚点
// (指示内核中过滤点的相对位置;
// 锚点应位于内核中;
// 默认值Point(-1,-1),表示锚点位于内核中心)
// 第6个参数 delta变量(可以调整亮度)
// 第7个参数 borderType
//均值滤波
// int k=15;
// Mat shuchu=Mat::ones(k,k,CV_32F)/(float)(k*k);//类似于归一化,都成小数,后面imshow得时候会把小数*255
// Mat src;
// filter2D(change,src,-1,shuchu);
//自定滤波
Mat juanji=(Mat_(2,2)<<0,1,8,5);
Mat src;
filter2D(change,src,CV_32F,juanji,Point(-1,-1));
// convertScaleAbs(src,src);
namedWindow("src",WINDOW_FREERATIO);
imshow("src",src);
}
void QuickDemo::tuxiangtidu(cv::Mat &change){
//梯度,卷积得一种,图片得轮廓,色差值大得地方
//robot算子x:1,0,0,-1 y:0,1,-1,0(轮廓不明显)
//CV_32F
Mat jx=(Mat_(2,2)<<1,0,0,-1);
Mat jy=(Mat_(2,2)<<0,1,-1,0);
Mat sx,sy;
filter2D(change,sx,CV_32F,jx,Point(-1,-1),0);
filter2D(change,sy,CV_32F,jy,Point(-1,-1),0);
convertScaleAbs(sx,sx);
convertScaleAbs(sy,sy);
Mat reslult;
add(sx,sy,reslult);
imshow("jieguo",reslult);
//Sobel算子:1:输入,2.输出3.深度,4.x方向 5.y方向6.ksize越大越明显
Sobel(change,sx,CV_32F,1,0);
Sobel(change,sy,CV_32F,0,1);
convertScaleAbs(sx,sx);
convertScaleAbs(sy,sy);
add(sx,sy,reslult);
imshow("Sobel",reslult);
//Scharr算子:1:输入,2.输出3.深度,4.x方向 5.y方向
Scharr(change,sx,CV_32F,1,0);
Scharr(change,sy,CV_32F,0,1);
convertScaleAbs(sx,sx);
convertScaleAbs(sy,sy);
add(sx,sy,reslult);
imshow("Scharr",reslult);
}
void QuickDemo::tuxiangbianyuanfaxian(cv::Mat &change){
// 拉普拉斯算子,二阶导数算子,提取图像轮廓,噪声对拉普拉斯影响较大
// 不用convertScaleAbs 深度用原图-1
Mat src;
Laplacian(change,src,-1,1);
imshow("lapulasi",src);
//图片锐化 算子:0,-1,0
// -1,5,-1
// 0,-1,0
Mat ruihua=(Mat_(3,3)<<0,-1,0,-1,5,-1,0,-1,0);
filter2D(change,src,CV_32F,ruihua,Point(-1,-1));
convertScaleAbs(src,src);
imshow("ruihua",src);
}
void QuickDemo::ruihua(cv::Mat &change){
// gaosi模糊-lapulasi
// lapu 得权重越大越锐化
Mat gaosi,lapu;
GaussianBlur(change,gaosi,Size(3,3),0);
GaussianBlur(change,change,Size(3,3),0);//高斯降噪锐化效果好
Laplacian(change,lapu,-1,1);
imshow("Laplacian",lapu);
Mat result;
addWeighted(gaosi,1.0,lapu,-2.0,0,result);
// namedWindow("ruihua",WINDOW_FREERATIO);
imshow("ruihua",result);
}
void QuickDemo::tuxiangzaosheng(cv::Mat &change){
//椒盐噪声
RNG rng(12345);
Mat yangcong=change.clone();
int num=100000;
for (int i=0;i(x,y)=Vec3b(255,255,255);
}
else {
yangcong.at(x,y)=Vec3b(0,0,0);
}
}
imshow("yangcong",yangcong);
//高斯噪声
Mat gaosi=Mat::zeros(change.size(),change.type());
//参数,均值(亮度)和方差(噪声程度)
randn(gaosi,Scalar(10,10,10),Scalar(100,100,100));
add(change,gaosi,gaosi);
imshow("gaosi",gaosi);
}
void QuickDemo::quzaosheng(cv::Mat &change){
RNG rng(12345);
Mat yangcong=change.clone();
int num=100000;
for (int i=0;i(x,y)=Vec3b(255,255,255);
}
else {
yangcong.at(x,y)=Vec3b(0,0,0);
}
}
imshow("yangcong",yangcong);
//中值滤波对椒盐噪声比较有效,原理抽取一块像素区,将里面像素值排列,取中间值
// 中值滤波函数-medianBlur
// -参数InputArray表示输入图像Mat对象
// -参数OutputArray表示模糊之后输出Mat对象
// -参数ksize表示卷积核大小,必须是正数而且必须是大于1,如:3、5、7等。
medianBlur(yangcong,yangcong,3);
imshow("去噪声",yangcong);
}
void QuickDemo::quzaoshenggs(cv::Mat &change){
//高斯噪声
Mat gaosi=Mat::zeros(change.size(),change.type());
//参数,均值(亮度)和方差(噪声程度)
randn(gaosi,Scalar(10,10,10),Scalar(50,50,50));
add(change,gaosi,gaosi);
imshow("噪声图像",gaosi);
//高斯双边去噪声、
Mat reault;
bilateralFilter(gaosi,reault,0,100,10);
imshow("高斯双边去噪声",reault);
//非局部均值滤波(对小噪声比较有效)
//7是卷积核大小,21是局部范围大小 h越大越模糊,最后一个参数一般是倒数第二得3到5倍
Mat fjbjzlb;
fastNlMeansDenoisingColored(gaosi,fjbjzlb,3,3,7,21);
imshow("非局部均值滤波",fjbjzlb);
cvtColor(gaosi,gaosi,COLOR_BGR2GRAY);
fastNlMeansDenoising(gaosi,fjbjzlb);
imshow("黑白非局部均值滤波",fjbjzlb);
}
void on_candy(int t1,void* tupian){
Mat src=*((Mat*)tupian);
//低于低阈值得像素点去除,高于高阈值得像素点保存
//1.输入 2.输出 3.t1低阈值 4.t2高阈值(为低阈值得2——3倍) 5.用默认值表示 Sobel 算子的孔径大小 6.默认用L1,快一点 为false
Mat result;
Canny(src,result,t1,t1*3,3,false);
// bitwise_and(src,src,dit,result);
namedWindow("结果",WINDOW_FREERATIO);
imshow("结果",result);
}
void QuickDemo::bianyuantiqu(cv::Mat &change){
int chushizhi=50;
int max=100;
createTrackbar("边缘程度:","原始",&chushizhi,max,on_candy,(void*)&change);
}
void QuickDemo::erzhituxiang(cv::Mat &change){
//二值图像就是像素点为0或者255得图像
//二值分割有5种方法(手动阈值)
// 1、THRESH_BINARY:将大于阈值的设为255,小于阈值的设为0
// 2、THRESH_BINARY_INV:将大于阈值的设为0,小于阈值的设为255
// 3、THRESH_TOZERO:将小于阈值的设为0,大于阈值的保留
// 4、THRESH_TOZERO_INV:将大于阈值的设为0,小于阈值的保留
// 5、THRESH_TRUNC:将大于阈值的值设置为阈值得值,小于阈值的保留
Mat gray,src;
cvtColor(change,gray,COLOR_BGR2GRAY);
//输入 输出 阈值 最大值 分割方法(要用灰度图像)
threshold(gray,src,171,255,THRESH_BINARY);
imshow("THRESH_BINARY",src);
threshold(gray,src,171,255,THRESH_BINARY_INV);
imshow("THRESH_BINARY_INV",src);
threshold(gray,src,171,255,THRESH_TOZERO);
imshow("THRESH_TOZERO",src);
threshold(gray,src,171,255,THRESH_TOZERO_INV);
imshow("THRESH_TOZERO_INV",src);
threshold(gray,src,171,255,THRESH_TRUNC);
imshow("THRESH_TRUNC",src);
}
void QuickDemo::erzhituxiangquanjuyuzhi(cv::Mat &change){
// 全局分割方法:1.均值法
// 2.直方图法(最优法)THRESH_OTSU
// 3.三角法(对单峰直方图效果好)THRESH_TRIANGLE(2,3自动阈值)
Mat gray,src;
cvtColor(change,gray,COLOR_BGR2GRAY);
Scalar m=mean(gray);
threshold(gray,src,m[0],255,THRESH_BINARY);
imshow("均值法",src);
threshold(gray,src,0,255,THRESH_OTSU);
imshow("THRESH_OTSU",src);
threshold(gray,src,0,255,THRESH_TRIANGLE);
imshow("THRESH_TRIANGLE",src);
// cout < qianjingheji(qianjing);
qianjingheji[0]=Vec3b(0,0,0);
RNG rng(12345);
for (int i=1;i(i,j);
result.at(i,j)=qianjingheji[huiduzhi];
}
}
putText(result,format("number:%d",qianjing),Point(50,50),FONT_HERSHEY_COMPLEX,1.0,Scalar(255,0,255),2,LINE_AA);
imshow("result",result);
}
void QuickDemo::tiquqianjingdaitongjixinxi(cv::Mat &change){
// connectedComponentsWithStats
// InputArray image, // 输入二值图像
// OutputArray labels, // 输出的标记图像,背景index=0
// OutputArray stats, // 统计信息,包括每个组件的位置、宽、高与面积//像素值为int
// OutputArray centroids, // 每个组件的中心位置坐标cx, cy//像素值为double
// int connectivity, // 连通域,默认是8连通
// int ltype, // 输出的labels类型,默认是CV_32S
// int ccltype // 连通组件算法
// 其中stats包括以下枚举类型数据信息:
// CC_STAT_LEFT 组件的左上角点像素点坐标的X位置
// CC_STAT_TOP 组件的左上角点像素点坐标的Y位置
// CC_STAT_WIDTH 组件外接矩形的宽度
// CC_STAT_HEIGHT 组件外接矩形的高度
// CC_STAT_AREA 当前连通组件的面积(像素单位)
//stats centroids得每一行相当于行数是连通域得值
GaussianBlur(change,change,Size(3,3),0);//高斯降噪
//转为二值图像
Mat gray,src,qianjingtu,stats,centroids;
cvtColor(change,gray,COLOR_RGB2GRAY);
threshold(gray,src,0,255,THRESH_BINARY|THRESH_OTSU);
imshow("二值",src);
int qianjing=connectedComponentsWithStats(src,qianjingtu,stats,centroids,8,CV_32S,CCL_DEFAULT);
vector qianjingheji(qianjing);
qianjingheji[0]=Vec3b(0,0,0);
RNG rng(12345);
for (int i=1;i(i,j);
result.at(i,j)=qianjingheji[huiduzhi];
}
}
for (int i=1;i(i,0);
int py=centroids.at(i,1);
int zsjx=stats.at(i,CC_STAT_LEFT);
int zsjy=stats.at(i,CC_STAT_TOP);
int w=stats.at(i,CC_STAT_WIDTH);
int h=stats.at(i,CC_STAT_HEIGHT);
int area=stats.at(i,CC_STAT_AREA);
circle(result,Point(px,py),2,Scalar(0,0,255),1,LINE_AA);
rectangle(result,Rect(zsjx,zsjy,w,h),Scalar(0,0,255),1,LINE_AA);
putText(result,format("%d",area),Point(zsjx,zsjy),FONT_HERSHEY_COMPLEX,0.5,Scalar(255,0,255),1,LINE_AA);
}
imshow("result",result);
}
void QuickDemo::lunkuofaxian(cv::Mat &change){
// findContours(
// InputArray image,
// OutputArrayOfArrays contours,
// OutputArray hierarchy,
// int mode,
// int method,
// Point offset = Point()
// )
//参数一: image,输入图像、八位单通道的,背景为黑色的二值图像。(一般是经过Canny、拉普拉斯等边缘检测算子处理过的二值图像)
//参数二:contours,输出轮廓图像。是一个向量,向量的每个元素都是一个轮廓。因此,这个向量的每个元素仍是一个向量。即:
// vector > contours;
//参数三:hierarchy,输出各个轮廓的继承关系。hierarchy也是一个向量,长度和contours相等,每个元素和contours的元素对应。
// hierarchy的每个元素是一个包含四个整型数的向量。即:分别表示后一个轮廓、前一个轮廓、父轮廓、内嵌轮廓的索引编号,如果没有对应项,则该值为负数。
// vector hierarchy;
//参数四:mode,检测轮廓的方法。有四种方法:
// RETR_EXTERNAL:只检测外轮廓。忽略轮廓内部的洞。
// RETR_LIST:检测所有轮廓,但不建立继承(包含)关系。
// RETR_TREE:检测所有轮廓,并且建立所有的继承(包含)关系。
// RETR_CCOMP:检测所有轮廓,但是仅仅建立两层包含关系。
//参数五:method,每个轮廓的编码信息。也有四种(常用前两种)
// CHAIN_APPROX_NONE:把轮廓上所有的点存储。
// CHAIN_APPROX_SIMPLE:只存储轮廓上的拐点。
// CHAIN_APPROX_TC89_L1,CHAIN_APPROX_TC89_KCOS使用teh-Chinl chain 近似算法
// drawContours(
// InputOutputArray binImg, // 输出图像
// OutputArrayOfArrays contours,// 全部发现的轮廓对象
// Int contourIdx// 轮廓索引号,-1表示绘制所有轮廓
// const Scalar & color,// 绘制时候颜色
// int thickness,// 绘制线宽,-1表示填充轮廓内部
// int lineType,// 线的类型LINE_8
// InputArray hierarchy,// 拓扑结构图
// int maxlevel,// 最大层数,0只绘制当前的,1表示绘制绘制当前和他的子轮廓 2再画一个子轮廓
// Point offset = Point()// 轮廓位移,可选
// )
Mat gray,src;
GaussianBlur(change,change,Size(3,3),0);
cvtColor(change,gray,COLOR_BGR2GRAY);
threshold(gray,src,0,255,THRESH_BINARY_INV|THRESH_OTSU);
imshow("THRESH_OTSU",src);
vector> contours;
vector hierarchy;
// Mat cc=Mat::zeros(change.size(),change.type());
findContours(src,contours,hierarchy,RETR_EXTERNAL,CHAIN_APPROX_SIMPLE);
drawContours(change,contours,-1,Scalar(0,0,255),3,LINE_AA/*,hierarchy,1*/);
imshow("jieguo",change);
}
void QuickDemo::lunkuojisuan(cv::Mat &change){
Mat gray,src;
GaussianBlur(change,change,Size(3,3),0);
cvtColor(change,gray,COLOR_BGR2GRAY);
threshold(gray,src,0,255,THRESH_BINARY|THRESH_OTSU);
imshow("THRESH_OTSU",src);
vector> contours;
vector hierarchy;
findContours(src,contours,hierarchy,RETR_TREE,CHAIN_APPROX_SIMPLE);
for (vector>::size_type i{};i> geshizhengli(cv::Mat &change){
Mat gray,src;
GaussianBlur(change,change,Size(3,3),0);
cvtColor(change,gray,COLOR_BGR2GRAY);
threshold(gray,change,0,255,THRESH_BINARY|THRESH_OTSU);
vector> contours;
vector hierarchy;
findContours(change,contours,hierarchy,RETR_EXTERNAL,CHAIN_APPROX_NONE,Point());
return contours;
}
void QuickDemo::lunkuopipei(cv::Mat &change){
Mat change2=imread("E:\\BaiduNetdiskDownload\\1.png",IMREAD_ANYCOLOR);
auto contours=geshizhengli(change);
auto contours2=geshizhengli(change2);
imshow("1",change);
imshow("2",change2);
//几何矩计算//几何矩可以用来计算hu矩,也可以求轮廓中心点
Moments jh2=moments(contours2[0]);
//hu矩计算
Mat hu2;
HuMoments(jh2,hu2);
for (vector>::size_type i{};i保存轮廓逼近输出的折点。
// epsilon: 轮廓逼近的顶点距离真实轮廓曲线的最大距离,该值越小表示越逼近真实轮廓。
// close: 表示是否为闭合区域。
Mat jieguo=change.clone();
auto contours=geshizhengli(change);
imshow("geshi",change);
vector> approxCurve(contours.size());
for (vector>::size_type i=0;i10) {
putText(jieguo,"yuan",Point(yx,yy),FONT_HERSHEY_COMPLEX,2,Scalar(88,88,88),1);
}
}
imshow("jieguo",jieguo);
}
void QuickDemo::nihe(cv::Mat &change){
//最小外接圆拟合
// void minEnclosingCircle( InputArray points,Point2f& center,
// float& radius );
// 1points:由点集组成的轮廓。
// 2center:输出圆心坐标。
// 3radius:输出圆的半径。
Mat waijie=change.clone();
Mat neijie=change.clone();
auto contours=geshizhengli(change);
imshow("geshi",change);
for (vector>::size_type i=0;i>::size_type x=0;x(i,j)=(float)pointPolygonTest(contours[x],Point2f((float)j,(float)i),true);//点得x对应图像得列也就是宽度
}
}
double max{};
double min{};
Point maxp,minp;
minMaxLoc(julichucun,&min,&max,&minp,&maxp);
circle(neijie,maxp,max,Scalar(255,255,255),2,LINE_AA);
}
imshow("neijie",neijie);
}
void QuickDemo::tuoyuannihe(cv::Mat &change){
//椭圆拟合
Mat caise=change.clone();
auto contours=geshizhengli(change);
imshow("2z",change);
for (vector>::size_type x=0;x5) {
drawContours(caise,contours,x,Scalar(0,0,255),2,LINE_AA);
RotatedRect xzjx=fitEllipse(contours[x]);//fitEllipse函数要求轮廓至少要有5个点
ellipse(caise,xzjx,Scalar(99,99,99),2,LINE_AA);
}
}
imshow("caise",caise);
}
void QuickDemo::huofuzhixian(cv::Mat &change){
// void HoughLines(InputArray image, OutputArray lines, double rho, double theta, int threshold, double srn=0, double stn=0 )
// 参数:
// image:边缘检测的输出图像. 它应该是个灰度图 (但事实上是个二值化图)
// lines:储存着检测到的直线的参数对 的容器 // vector类型,分别是距离角度累加值
// rho:参数极径 以像素值为单位的分辨率. 我们使用 1 像素.
// theta:参数极角 以弧度为单位的分辨率. 我们使用 1度 (即CV_PI/180)
// theta:要”检测” 一条直线所需最少的的曲线交点,直线交点得阈值,也就是vec3f得最后一个值,累加值,越大直线越少
// srn and stn: 参数默认为0.
Mat xian=change.clone(),gray;
cvtColor(change,gray,COLOR_BGR2GRAY);
threshold(gray,change,0,255,THRESH_BINARY|THRESH_OTSU);
imshow("erzhi",change);
vector lines;
HoughLines(change,lines,1,CV_PI/180.0,150);
Point p1,p2;//画直线得两个顶点
for (vector::size_type i{};i0) {
line(xian,p1,p2,Scalar(0,0,255),2,LINE_AA);
if (jiaodu==90) {//水平线
line(xian,p1,p2,Scalar(25,18,25),2,LINE_AA);
}
if(jiaodu<=1){//垂直线
line(xian,p1,p2,Scalar(0,255,0),2,LINE_AA);
}
}else {//长度为负得数是往左边倾斜得
line(xian,p1,p2,Scalar(255,0,0),2,LINE_AA);
}
}
imshow("结果",xian);
}
void QuickDemo::huofuzhixian2(cv::Mat &change){
// HoughLinesP(
// InputArray src, // 输入图像,必须8-bit的灰度图像
// OutputArray lines, // 输出的极坐标来表示直线//vector
// double rho, // 生成极坐标时候的像素扫描步长,一般取1
// double theta, //生成极坐标时候的角度步长,一般取值CV_PI/180
// int threshold, // 阈值,要”检测” 一条直线所需最少的的曲线交点,直线交点得阈值
// double minLineLength=0;// 最小直线长度
// double maxLineGap=0;// 两交点间允许的最大间隔,(经canny的梯度可能不连续,间隔调大)
//霍夫直线前可以传统方法转换为二值图像,也可以用canny转化为二值图像
Mat jieguo=change.clone(),bianyuan;
Canny(change,bianyuan,80,160,3,false);
imshow("bianyuan",bianyuan);
vector lines;
HoughLinesP(bianyuan,lines,1,CV_PI/180.0,100,100,20);
for (vector::size_type i{};i
// Int method, // 方法 - HOUGH_GRADIENT
// Double dp, // dp = 1; 越大检测越多
// Double mindist, // 10 最短距离-可以分辨是两个圆的,否则认为是同心圆- src_gray.rows/8//圆心之间得最小距离
// Double param1, // canny高阈值低阈值默认为它的一半
// Double param2, // 中心点累加器阈值 ? 候选圆心,累加交点阈值
// Int minradius, // 最小半径
// Int maxradius//最大半径
// )
//传入灰度图像并降噪//霍夫直线和圆都对噪声敏感,降噪效果更好
Mat gaosi,gray;
GaussianBlur(change,gaosi,Size(3,3),5);
cvtColor(gaosi,gray,COLOR_BGR2GRAY);
imshow("zhuanhuan",gray);
vector circles;
HoughCircles(gray,circles,HOUGH_GRADIENT,2,60,130,130,20,70);
for (vector::size_type i{};i> contours;
vector hierarchy;
findContours(bi,contours,hierarchy,RETR_EXTERNAL,CHAIN_APPROX_SIMPLE);
double maxmianji{};
int xuhao{};
for (vector>::size_type i{};imaxmianji) {
maxmianji=mianji;
xuhao=i;
}
}
drawContours(change,contours,xuhao,Scalar(0,0,255),2,LINE_AA);
vector guaidian(contours[xuhao].size());
approxPolyDP(contours[xuhao],guaidian,4,true);
for (vector::size_type i{};i(hang,lie)>100) {
circle(change,Point(lie,hang),2,Scalar(0,0,255),-1,LINE_AA);
}
}
}
imshow("jieguo",change);
}
void QuickDemo::shi_tomasi_jiaodianjiance(cv::Mat &change){
// goodFeaturesToTrack()
// image:输入图像,一般是灰度图像
// 检测到的角点。vector
// maxCorners: 角点得最大数量
// qualtyLevel: 角点的质量水平,0-1之间。它代表了角点的最低质量,实际用于过滤角点的最小特征值是qualtyLevel与图像中最大特征值的乘积,
// 所以qualtyLevel的值不应超过1(常用的值为0.1或0.01)。低于这个值的所有角点都会被忽略。
// minDistance: 两个角点之间的最短距离。
// mask:
// blockSize:计算导数的自相关矩阵时指定点的领域,默认为3,采用小窗口计算的结果比单点(也就是blockSize为1)计算的效果要好。
// useHarrisDetector: 默认值为0,若非0,则函数使用Harris的角点定义
// K: 当 useHarrisDetector非0,则K为用于设置hessian自相关矩阵即对hessian行列式的相对权值的权值系数。
Mat gray;
cvtColor(change,gray,COLOR_BGR2GRAY);
vector jiaodianjihe;
goodFeaturesToTrack(gray,jiaodianjihe,100,0.1,10);
for (vector::size_type i{};i> contours;
vector hierarchy;
findContours(mask,contours,hierarchy,RETR_EXTERNAL,CHAIN_APPROX_SIMPLE);
RotatedRect rrt=minAreaRect(contours[0]);
circle(tupian,rrt.center,2,Scalar(0,0,255),1,LINE_AA);
ellipse(tupian,rrt,Scalar(255,0,255),2,LINE_AA);
imshow("jieguo",tupian);
if(waitKey(16)==27){
break;
}
}
}
video.release();
}
void QuickDemo::beijingjianmo(cv::Mat &change){
// BackgroundSubtractorMOG2创建及初始化
// history:用于训练背景的帧数,默认为500帧,如果不手动设置learningRate,history就被用于计算当前的learningRate,此时history越大,learningRate越小,背景更新越慢;
// varThreshold:方差阈值,用于判断当前像素是前景还是背景。一般默认16,如果光照变化明显,如阳光下的水面,建议设为25,36,具体去试一下也不是很麻烦,值越大,灵敏度越低;
// detectShadows:是否检测影子,设为true为检测,false为不检测,检测影子会增加程序时间复杂度,如无特殊要求,建议设为false;
// mog->apply(src_YCrCb, foreGround, 0.005);
// image 源图
// fmask 前景(二值图像)
// learningRate 学习速率,值为0-1,为0时背景不更新,为1时逐帧更新,默认为-1,即算法自动更新;
VideoCapture video("E:\\BaiduNetdiskDownload\\vtest.avi");
Ptr mog = createBackgroundSubtractorMOG2();
Mat kernel=getStructuringElement(MORPH_RECT,Size(5,5));
if (video.isOpened())
{
Mat tupian;
while (true) {
video.read(tupian);//读没了返回false并且传入空图像
if (tupian.empty()) {
break;
}
imshow("shiping",tupian);
Mat mask(tupian.size(),CV_8UC1);
mog->apply(tupian,mask);
morphologyEx(mask,mask,MORPH_OPEN,kernel,Point(-1,-1),1);
morphologyEx(mask,mask,MORPH_CLOSE,kernel,Point(-1,-1),1);
vector> lunkuodian;
vector kuopujiegou;
findContours(mask,lunkuodian,kuopujiegou,RETR_EXTERNAL,CHAIN_APPROX_SIMPLE);
for (vector>::size_type i{};i80) {
Rect juxing=boundingRect(lunkuodian[i]);
rectangle(tupian,juxing,Scalar(0,0,255),2,LINE_AA);
}
}
imshow("jieguo",mask);
imshow("jieguo2",tupian);
if(waitKey(16)==27){
break;
}
}
}
video.release();
}
void QuickDemo::orbguanjiandian(cv::Mat &change){
// ORB对象创建,
// Orb = cv::ORB::create(500)
// virtual void cv::Feature2D::detect(
// InputArray image, // 输入图像
// std::vector< KeyPoint > & keypoints, // 关键点
// InputArray mask = noArray() // 支持mask
// )
// KeyPoint数据结构-四个最重要属性:
// -pt 坐标
// -angle
// -response
// -size
auto orb=ORB::create(500);//500个关键点
vector keyp;
orb->detect(change,keyp);
drawKeypoints(change,keyp,change,Scalar::all(-1),DrawMatchesFlags::DEFAULT);//小点;
// drawKeypoints(change,keyp,change,Scalar::all(-1),DrawMatchesFlags::DRAW_RICH_KEYPOINTS);//大圈体现出keypoint得angle,pt,size
imshow("jieguo",change);
}
void QuickDemo::orbmiaoshuzi(cv::Mat &change){
auto orb=ORB::create(500);//500个关键点
vector keyp;
orb->detect(change,keyp);
Mat miaoshuzi;
orb->compute(change,keyp,miaoshuzi);
cout < ky;
sift->detect(img,ky);
drawKeypoints(img,ky,img,Scalar::all(-1),DrawMatchesFlags::DEFAULT);
imshow("dd",img);
Mat miaoshuzi;
sift->compute(img,ky,miaoshuzi);
cout < ky;
vector ky_dest;
Mat miaoshuzi;
Mat miaoshuzi_dest;
Mat imgdest=cv::imread("E:/Desktop/study/class_tezheng/src/book_on_desk.jpg");
orb->detectAndCompute(img,Mat(),ky,miaoshuzi);
orb->detectAndCompute(imgdest,Mat(),ky_dest,miaoshuzi_dest);
//暴力匹配
auto baoli=BFMatcher::create(NORM_HAMMING);
vector qipeijieguo;
Mat result;
// baoli->knnMatch(miaoshuzi,miaoshuzi_dest,qipeijieguo,2);
baoli->match(miaoshuzi,miaoshuzi_dest,qipeijieguo);
drawMatches(img,ky,imgdest,ky_dest,qipeijieguo,result);
imshow("baoli",result);
//flann匹配
auto fannlmatch=FlannBasedMatcher(new flann::LshIndexParams(6,12,2));
vector flannqipeijieguo;
Mat result_flann;
fannlmatch.match(miaoshuzi,miaoshuzi_dest,flannqipeijieguo);
drawMatches(img,ky,imgdest,ky_dest,flannqipeijieguo,result_flann);
imshow("flann",result_flann);
}
void QuickDemo::siftqipei(cv::Mat &img){
auto sift=SIFT::create(500);
vector ky;
vector ky_dest;
Mat miaoshuzi;
Mat miaoshuzi_dest;
Mat imgdest=cv::imread("E:/Desktop/study/class_tezheng/src/book_on_desk.jpg");
sift->detectAndCompute(img,Mat(),ky,miaoshuzi);
sift->detectAndCompute(imgdest,Mat(),ky_dest,miaoshuzi_dest);
//暴力
auto baoli=BFMatcher::create(NORM_L1,false);
vector qipeijieguo;
Mat result;
baoli->match(miaoshuzi,miaoshuzi_dest,qipeijieguo);
drawMatches(img,ky,imgdest,ky_dest,qipeijieguo,result);
imshow("jieguo",result);
//flann匹配
auto fannlmatch=FlannBasedMatcher(new flann::KDTreeIndexParams());
// auto fannlmatch=FlannBasedMatcher();
vector flannqipeijieguo;
Mat result_flann;
fannlmatch.match(miaoshuzi,miaoshuzi_dest,flannqipeijieguo);
sort(flannqipeijieguo.begin(),flannqipeijieguo.begin(),[](const DMatch qian,const DMatch hou){return qian.distance ky;
vector ky_dest;
Mat miaoshuzi;
Mat miaoshuzi_dest;
Mat imgdest=cv::imread("E:/Desktop/study/class_tezheng/src/book_on_desk.jpg");
orb->detectAndCompute(img,Mat(),ky,miaoshuzi);
orb->detectAndCompute(imgdest,Mat(),ky_dest,miaoshuzi_dest);
//暴力匹配
auto baoli=BFMatcher::create(NORM_HAMMING,false);
vector qipeijieguo;
Mat result;
baoli->match(miaoshuzi,miaoshuzi_dest,qipeijieguo);
sort(qipeijieguo.begin(),qipeijieguo.end(),[](const DMatch &a,const DMatch &b){return a.distance qAffinePts;
vector hAffinePts;
for (size_t t = 0; t < qipeijieguo.size(); t++) {
qAffinePts.push_back(ky[qipeijieguo[t].queryIdx].pt);
hAffinePts.push_back(ky_dest[qipeijieguo[t].trainIdx].pt);
}
Mat M = findHomography(qAffinePts,hAffinePts,RANSAC);//还可以用rho
vector q{Point2f(0,0),Point2f(img.cols,0),Point2f(img.cols,img.rows),Point2f(0,img.rows)};
vector h(4);
perspectiveTransform(q, h, M);//这个透视变换适用于特征提取然后获取在图像中的点
for(int i{};i<4;++i){
line(imgdest,h[i],h[(i+1)%4],Scalar(0,0,255),2,LINE_AA);
}
imshow("jg",imgdest);
}
void QuickDemo::wendangduiqi(cv::Mat &img){
auto orb=ORB::create(500);
vector ky;
vector ky_dest;
Mat miaoshuzi;
Mat miaoshuzi_dest;
Mat imgdest=cv::imread("E:/Desktop/study/class_tezheng/src/form.png");
orb->detectAndCompute(img,Mat(),ky,miaoshuzi);
orb->detectAndCompute(imgdest,Mat(),ky_dest,miaoshuzi_dest);
//暴力匹配
auto baoli=BFMatcher::create(NORM_HAMMING,false);
vector qipeijieguo;
Mat result;
baoli->match(miaoshuzi,miaoshuzi_dest,qipeijieguo);
sort(qipeijieguo.begin(),qipeijieguo.end(),[](const DMatch &a,const DMatch &b){return a.distance qAffinePts;
vector hAffinePts;
for (size_t t = 0; t < qipeijieguo.size(); t++) {
qAffinePts.push_back(ky[qipeijieguo[t].queryIdx].pt);
hAffinePts.push_back(ky_dest[qipeijieguo[t].trainIdx].pt);
}
Mat M = findHomography(qAffinePts,hAffinePts,RANSAC);//还可以用rho
Mat DstImg;
warpPerspective(img, DstImg, M,Size(imgdest.cols,imgdest.rows));
imshow("jieguo",DstImg);
}
void QuickDemo::tiaomabiaoqiandingwei(cv::Mat &left){
}
//交叉匹配
//针对暴力匹配,可以使用交叉匹配的方法来过滤错误的匹配。交叉过滤的思想很简单,再进行一次匹配,反过来使用被匹配到的点进行匹配,如果匹配到的仍然是第一次匹配的点的话,就认为这是一个正确的匹配。举例来说就是,假如第一次特征点A使用暴力匹配的方法,匹配到的特征点是特征点B;反过来,使用特征点B进行匹配,如果匹配到的仍然是特征点A,则就认为这是一个正确的匹配,否则就是一个错误的匹配。OpenCV中BFMatcher已经封装了该方法,创建BFMatcher的实例时,第二个参数传入true即可,BFMatcher bfMatcher(NORM_HAMMING,true)。
//KNN匹配
//K近邻匹配,在匹配的时候选择K个和特征点最相似的点,如果这K个点之间的区别足够大,则选择最相似的那个点作为匹配点,通常选择K = 2,也就是最近邻匹配。对每个匹配返回两个最近邻的匹配,如果第一匹配和第二匹配距离比率足够大(向量距离足够远),则认为这是一个正确的匹配,比率的阈值通常在2左右。
//OpenCV中的匹配器中封装了该方法,上面的代码可以调用bfMatcher->knnMatch(descriptors1, descriptors2, knnMatches, 2);
void QuickDemo::jingzita(cv::Mat &change){
// pyrUp(Mat src,Mat dst,Size(src.cols*2,src.rows*2))生成的图像是原图在宽与高各放大二倍
// pyrDown(Mat src,Mat dst,Size(src.cols/2,src.rowa/2))生成的图像是原图在宽和高都缩小1/2
//拉普拉斯金字塔就是使用原始图像减去图像向下取样然后向上取样的这样一个过程。
// Li = Gi - PyrUp(PyrDown(Gi))
Mat dst;
// pyrUp(change,dst);
// imshow("dst",dst);
// pyrUp(change,dst,Size(change.cols*2,change.rows*2));
// imshow("dst1",dst);
pyrDown(change,dst);
imshow("dst",dst);
pyrDown(change,dst,Size(change.cols/2,change.rows/2));
imshow("dst1",dst);
}
void QuickDemo::julibianhuan(cv::Mat &change){
//Opencv中distanceTransform方法用于计算图像中每一个非零点距离离自己最近的零点的距离
// void distanceTransform(InputArray src,
// OutputArray dst,
// int distanceType,
// int maskSize,
// int dstType=CV_32F
// )
// dstType:输出图像(矩阵)的数据类型,可以是CV_8U 或 CV_32F。当选择CV_8U时,distanceType的类型只能为DIST_L1。
// src:源矩阵
// dst:目标矩阵
// distanceType:距离类型,可选的类型如下:
// DIST_USER
// User defined distance.
// DIST_L1
// distance = |x1-x2| + |y1-y2|
// DIST_L2
// the simple euclidean distance
// DIST_C
// distance = max(|x1-x2|,|y1-y2|)
// DIST_L12
// L1-L2 metric: distance = 2(sqrt(1+x*x/2) - 1))
// DIST_FAIR
// distance = c^2(|x|/c-log(1+|x|/c)), c = 1.3998
// DIST_WELSCH
// distance = c^2/2(1-exp(-(x/c)^2)), c = 2.9846
// DIST_HUBER
// distance = |x|> approxCurve(contours.size());
for (vector>::size_type i=0;i dianji{approxCurve[0][0],approxCurve[0][1],approxCurve[0][2],approxCurve[0][3]};
int w=change.cols/2;
int h=change.rows/2;
for (vector ::size_type i{};iw&&approxCurve[0][i].yh) {
auto zhongjie=approxCurve[0][2];
approxCurve[0][2]=approxCurve[0][i];
approxCurve[0][i]=zhongjie;
}
if (approxCurve[0][i].x>w&&approxCurve[0][i].y>h) {
auto zhongjie=approxCurve[0][3];
approxCurve[0][3]=approxCurve[0][i];
approxCurve[0][i]=zhongjie;
}
}
double widthmax=pow(pow((approxCurve[0][1].x-approxCurve[0][0].x),2)+pow((approxCurve[0][1].y-approxCurve[0][0].y),2),(double)1.0/2);
double heightmax=pow(pow((approxCurve[0][2].x-approxCurve[0][0].x),2)+pow((approxCurve[0][2].y-approxCurve[0][0].y),2),(double)1.0/2);
Mat src;
Point2f SrcAffinePts[4] = { Point2f(approxCurve[0][0]),Point2f(approxCurve[0][1]) ,Point2f(approxCurve[0][2]) ,Point2f(approxCurve[0][3])};
Point2f DstAffinePts[4] = { Point2f(0,0),Point2f(widthmax,0),Point2f(0,heightmax),Point2f(widthmax,heightmax)};
Mat M = getPerspectiveTransform(SrcAffinePts, DstAffinePts);
Mat DstImg;
warpPerspective(jieguo, DstImg, M,Point(widthmax,heightmax));
imshow("jg",DstImg);
// TextRecognitionModel
}
void QuickDemo::tiaomabiaoqiandingwei(Mat &img){
auto orb=ORB::create(500);
vector ky;
vector ky_dest;
Mat miaoshuzi;
Mat miaoshuzi_dest;
Mat imgdest=cv::imread("E:/Desktop/study/class_tezheng/src/orb_barcode/00059-NG.jpg",WINDOW_FREERATIO);
orb->detectAndCompute(img,Mat(),ky,miaoshuzi);
orb->detectAndCompute(imgdest,Mat(),ky_dest,miaoshuzi_dest);
//暴力匹配
auto baoli=BFMatcher::create(NORM_HAMMING,false);
vector qipeijieguo;
Mat result;
baoli->match(miaoshuzi,miaoshuzi_dest,qipeijieguo);
sort(qipeijieguo.begin(),qipeijieguo.end(),[](const DMatch &a,const DMatch &b){return a.distance qAffinePts;
vector hAffinePts;
for (size_t t = 0; t < qipeijieguo.size(); t++) {
qAffinePts.push_back(ky[qipeijieguo[t].queryIdx].pt);
hAffinePts.push_back(ky_dest[qipeijieguo[t].trainIdx].pt);
}
Mat M = findHomography(qAffinePts,hAffinePts,RANSAC);//还可以用rho
vector q{Point2f(0,0),Point2f(img.cols,0),Point2f(img.cols,img.rows),Point2f(0,img.rows)};
vector h(4);
perspectiveTransform(q, h, M);//这个透视变换适用于特征提取然后获取在图像中的点
sort(h.begin(),h.end(),[](const Point2f &a,const Point2f &b){return a.yh[1].x){
temp=h[0];
h[0]=h[1];
h[1]=temp;
}
if(h[2].x>h[3].x){
temp=h[2];
h[2]=h[3];
h[3]=temp;
}
Rect roi(h[0],h[3]);
Mat src(imgdest(roi));
transpose(src,src); //转置
flip(src,src,0) ;
namedWindow("roi",1);
imshow("roi",src);
// flip(Mat src,Mat &dst,int nFlag);//镜像
}
string objNames[] = { "background",
"aeroplane", "bicycle", "bird", "boat",
"bottle", "bus", "car", "cat", "chair",
"cow", "diningtable", "dog", "horse",
"motorbike", "person", "pottedplant",
"sheep", "sofa", "train", "tvmonitor" };
void QuickDemo::wutishibie(cv::Mat &img){
string modeltextf="E:/BaiduNetdiskDownload/model/MobileNetSSD_deploy.prototxt";
string modelfile="E:/BaiduNetdiskDownload/model/MobileNetSSD_deploy.caffemodel";
Net net=readNetFromCaffe(modeltextf,modelfile);
Mat blob=blobFromImage(img,0.007843,Size(300,300),Scalar(127.5, 127.5, 127.5),false,false);
net.setInput(blob);
Mat src=net.forward();
Mat result(src.size[2],src.size[3],CV_32F,src.ptr());
for (int i{};i(i);
pt+=1;
size_t fenlei=(size_t)(*pt++);
float yuzhi=*pt++;
if (yuzhi>0.5) {
float x1=(*pt++)*img.cols;
float y1=(*pt++)*img.rows;
float x2=(*pt++)*img.cols;
float y2=(*pt++)*img.rows;
Rect biankuang(Point(x1,y1),Point(x2,y2));
rectangle(img,biankuang,Scalar(0,0,255),2,LINE_AA);
putText(img,string(objNames[fenlei]),Point(x1,y1-5),FONT_HERSHEY_COMPLEX,1.0,Scalar(45,18,77),1,LINE_AA);
}
}
imshow("img",img);
}