1.C++
1.1 面向对象
①类
个人理解:类就是一种简单的数据结构,或者可以说就是像int、float等定义的数据类型。只不过类是我们自己定义的一种数据类型(里面可以包含成员变量,成员函数)
②继承(is a)
依据一个类来定义子类,重用代码,提高执行时间(class sub-class:base-class1,base-class2……)
③重载
同一作用域中,某个函数或运算符做多个定义,函数重载(参数个数、类型、顺序),运算符重载(关键字operater)
1.2 异常处理--详见代码(try中设置抛出throw,catch中捕获)
/*****
try的保护代码块有抛出throw,后面catch才能捕获
*****/
#include <iostream>
using namespace std;
double divide(double a, double b)
{
if(b==0)
{
throw "zero exception";
}
return (a/b);
}
int main(int argc, char const *argv[])
{
try{//放可能抛出异常的代码--保护代码
cout<<divide(3,0)<<endl;//这里并不能直接抛出异常
}
catch(const char *msg)//需要用catch捕获异常---try的保护代码区若有多个异常,则需要多个catch捕获
{
cerr<<msg<<endl;
}
return 0;
}
1.3 内存
函数中声明的所有变量--栈内存
程序中未用到的内存,程序运行时动态分配--堆内存(new/delete)
double* pvalue = NULL; // 初始化为 null 的指针
pvalue = new double; // 为变量请求内存
new--为变量请求内存,返回分配的空间的地址。(一般不知道变量需要多大内存时使用)
new与C语言中的malloc区别在于,new不仅分配内存,还创建对象。
1.4 随机数组
/*产生[left,right]区间的包含N个数的随机数组*/
int *randArray(int left, int right, int N)
{
int *arr = new int[N];
srand((unsigned)time(NULL));//产生随机数种子
for (int i = 0; i<N; i++)
{
arr[i] = (left+rand()%(right-left));
}
return arr;
}
注意:①头文件需要include<ctime> #include<cstdlib>。②这里new了一个内存空间,需要delete[]。
但仍然存在一个问题:返回后得到的数组长度是2,还没搞懂是为什么?
同时附上一个python语言实现的从start到end的随机数组(长度为proportion*10):
import os
import random
def rand_index_list(start=0,end=9,proportion=1):
rand_index_list = []
while len(rand_index_list)<proportion*10:
rand_index=random.randint(start,end)
if rand_index not in rand_index_list:
rand_index_list.append(rand_index)
rand_index_list.sort()
return rand_index_list
def rand_serial(path_fold=None):
train_val_proportion = 0.8
rand_train_val_index_list=rand_index_list(proportion=train_val_proportion)
print("train_val_index:{}".format(rand_train_val_index_list))
train_proportion = 0.6
rand_train_index_list = [rand_train_val_index_list[x] for x in rand_index_list(start=0,end=train_proportion*10,proportion=train_proportion)]
print("train_index:{}".format(rand_train_index_list))
if __name__ == "__main__":
rand_serial()
1.5 插入排序
思想:从数组的第二个数(索引=1)开始,预先设定keyValue,分别与前面的数做对比,如果前面的数比keyValue小,则交换两者位置。因此,每轮排序后,keyValue前面都是排序好了的数组。
void insertSort(int *arr)
{
cout<<endl;
cout<<"before sort:"<<endl;
for (int index = 0; index < arrayLength; index++)
{
cout<<arr[index]<<" ";
}
cout<<"\nsizeof(arr) = "<<sizeof(arr)<<endl;
cout<<"the length of array is sizeof(arr)/sizeof(int) = "<<sizeof(arr)/sizeof(int)<<endl;
for(int index = 1; index<arrayLength; index++)
{
int sortedIndex = index-1;
int unsortedIndex = index;
int keyValue = arr[index];
while(keyValue >= arr[sortedIndex] && sortedIndex >= 0)
{
arr[unsortedIndex--] = arr[sortedIndex];
arr[sortedIndex] = keyValue;
sortedIndex--;
}
}
cout<<"after sort:"<<endl;
for (int index = 0; index < arrayLength; index++)
{
cout<<arr[index]<<" ";
}
cout<<endl;
}
其中arrayLength是4)中生成的数组长度。
1.6 冒泡排序
数组array[10]冒泡思想:
①第一轮:array[0]与array[1]对比交换,array[1]与array[2]对比交换……array[8]与array[9]对比交换,最终最大(或最小)的数被"冒泡"到最后一个位置;
②第二轮:array[0]与array[1]对比交换……array[7]与array[8]对比交换,因为array[9]在第①轮就已经被确定为最大(或最小)值;
……
/*思想:紧邻两个数进行对比交换,每一轮都会将最小的数交换到最后一个。
compareIndex<arrayLength-lunIndex表示每一轮"冒泡"完,就不用管后面"冒泡"好了的数*/
void bubleSort(int *arr)
{
for (int lunIndex = 0; lunIndex<arrayLength; lunIndex++)
{
for (int compareIndex = 1; compareIndex<arrayLength-lunIndex; compareIndex++)
{
if(arr[compareIndex]>arr[compareIndex-1])
{
int temp = arr[compareIndex];
arr[compareIndex]=arr[compareIndex-1];
arr[compareIndex-1]=temp;
}
}
}
}
1.7 选择排序
/*每一轮都选出其中最大值maxValue,分别与第1/2/3……交换位置*/
void selectSort(int *arr)
{
for (int index = 0; index<arrLength-1; index++)
{
int maxValue=0;
int maxValueIndex = 0;
//find the max number
for (int selectIndex = index+1; selectIndex<arrLength; selectIndex++)
{
if(arr[selectIndex]>=maxValue)
{
maxValue = arr[selectIndex];
maxValueIndex = selectIndex;
}
}
//exchange between maxValue with the value of index location
int tempValue = arr[index];
arr[index] = maxValue;
arr[maxValueIndex] = tempValue;
}
}
2.QT
2.1 配置
参考网址:https://blog.csdn.net/win_turn/article/details/50465127--亲测成功
为避免新旧版本兼容性,可查一下对应Qt是哪个版本的MinGW版本编译的,下载对应的安装包即可。
①MinGW安装:可下载压缩文件,解压后配好环境变量即可(path加入路径$mingw32\bin);
②Qt库安装:注意选择MinGW时,设置为$ming32的位置,提示“There is a problem with your MinGW installation:……”,则说明MinGW路径选择错误;
③QtCreater安装配置:(配置)工具->选项->Debuggers(Name自己定,Path设置为$mingw32\bin\gdb.exe)->编译器(手动设置Path为$mingw32\bin\g++.exe)->Qt Versions(选择qmake.exe)->构建套件Kit(编译器、调试器、Qt版本选择前几步设置好的Name)->新建项目(Qt Widgets Application,全部默认就行,左下角绿色三角形运行即可开始一个最简单的Qt开发界面)
2.2 对话框Dialog
①模式对话框(“主对话框”上生成一个“子对话框”,“主对话框”阻塞,必须关闭“子对话框”之后才能继续对“主对话框”进行操作。主要函数exec())
②非模式对话框(“主对话框”上生成一个“子对话框”,“主对话框”不会阻塞,可对“主/子对话框”同时操作。类似文字查找/替换功能。主要函数show())
③半模式对话框(“主对话框”上生成一个“子对话框”,“主对话框”阻塞。主要针对进度对话框,一定进度后仍需要交其具有信息交互能力。主要函数setModal(true),show())
3.c++基础知识
3.1 关键字explicit
参考:https://blog.csdn.net/qq_35524916/article/details/58178072
直观理解就是:防止隐式转换的。
使用情况:有时候我们需要防止隐式转换的发生,通过添加explicit实现,即需要显示调用函数。
参考网站中的构造函数冒号(:)就是初始化,使用解释可以查看:https://www.cnblogs.com/qingyuanhu/p/4301691.html
3.2 关键字inline
参考:https://www.cnblogs.com/fnlingnzb-learner/p/6423917.html
解释:调用函数时,会重新开辟栈内存,使用inline的内联函数,相当于把函数中的代码复制到调用的位置。因此函数里面的内容需要简单,不包括循环结构for、 while、 switch等。
3.3 编程报错Core Dump (Segmentation fault) in C/C++
参考:https://www.geeksforgeeks.org/core-dump-segmentation-fault-c-cpp/
- 修改只读内存
- 访问已被释放的地址
- 数组访问超出边界
3.OpenCV
3.1 获取图像像素值
图像读取imread函数执行之后,图像以Mat格式存储,获取图像某一像素值,有以下常用方式获取:
- 最简单:image.at<uchar>(i, j)或image.at<vec3d>(i, j)读取(i,j)处的像素值;(但是terminal上看不见输出结果,因为uchar类型以ASCII码显示,会隐藏,需要强制转换为int类型,参考)
3.2 sobel边缘检测算法
/****https://blog.csdn.net/u011486738/article/details/82256644
1.在C++中,内存分成5个区,他们分别是堆、栈、自由存储区、全局/静态存储区和常量存储区。
2.栈,就是那些由编译器在需要的时候分配,在不需要的时候自动清理的变量的存储区。里面的变量通常是局部变量、函数参数等。
3.堆,就是那些由new分配的内存块,他们的释放编译器不去管,由我们的应用程序去控制,一般一个new就要对应一个delete。如果程序员没有释放掉,那么在程序结束后,操作系统会自动回收。
4.自由存储区,就是那些由malloc等分配的内存块,他和堆是十分相似的,不过它是用free来结束自己的生命的。
5.全局/静态存储区,全局变量和静态变量被分配到同一块内存中,在以前的C语言中,全局变量又分为初始化的和未初始化的,在C++里面没有这个区分了,他们共同占用同一块内存区。
6.常量存储区,这是一块比较特殊的存储区,他们里面存放的是常量,不允许修改(当然,你要通过非正当手段也可以修改,而且方法很多)
不可return的变量:函数不能返回指向栈内存的指针或者引用
可return的变量:int类型,字符串常量(不能return字符串常量的引用),静态局部变量,堆内存中的局部变量(new出来的)
****/
#include "opencv2/core/core.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/calib3d/calib3d.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <iostream>
#include <fstream>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <dirent.h>
using namespace cv;
using namespace std;
bool changelabel=false; //用于协助查看图像像素值
vector<string> getFiles(string cate_dir)
{
vector<string> files;//存放文件名
DIR *dir;
struct dirent *ptr;
char base[1000];
if ((dir=opendir(cate_dir.c_str())) == NULL)
{
perror("Open dir error...");
exit(1);
}
while ((ptr=readdir(dir)) != NULL)
{
if(strcmp(ptr->d_name,".")==0 || strcmp(ptr->d_name,"..")==0) ///current dir OR parrent dir
continue;
else if(ptr->d_type == 8) ///file
//printf("d_name:%s/%s\n",basePath,ptr->d_name);
files.push_back(ptr->d_name);
else if(ptr->d_type == 10) ///link file
//printf("d_name:%s/%s\n",basePath,ptr->d_name);
continue;
else if(ptr->d_type == 4) ///dir
{
files.push_back(ptr->d_name);
/*
memset(base,'\0',sizeof(base));
strcpy(base,basePath);
strcat(base,"/");
strcat(base,ptr->d_nSame);
readFileList(base);
*/
}
}
closedir(dir);
//排序,按从小到大排序
sort(files.begin(), files.end());
return files;
}
/*把超过1的像素全部置为1,防止卷积计算时超过uchar类型的范围,
这样计算sobel算子(x方向:[[-1,0,1],[-2,0,2],[-1,0,1]];y方向:[[-1,-2,-1],[0,0,0],[1,2,1]])的时候,
最大也就为4*/
static Mat set_1_fun(Mat matrix)
{
/*不能直接修改传入函数的矩阵,否则会报错Segmentation fault (core dumped)必须通过新建一个临时矩阵,return
*/
int m[3][3] = {{0,0,0},{0,0,0},{0,0,0}};
static Mat temp_matrix=Mat(3,3,CV_8UC1,m);
Mat matrix1 = matrix;
uchar w=matrix1.cols;
uchar h=matrix1.rows;
for (int t_i=0;t_i<h;t_i++)
{
for (int t_j=0;t_j<w;t_j++)
{
uchar pixel_value = matrix1.ptr<uchar>(t_i)[t_j];
if (pixel_value>1)
{
//cout<<"pixel:"<<pixel_value<<endl;
temp_matrix.ptr<uchar>(t_i)[t_j] = (uchar)1;
}
}
}
return temp_matrix;
}
/*这里用static是为了将局部变量放置到静态存储区,才能返回正常值*/
static Mat get_temp_matrix(Mat matrix,int h_j,int w_i)
{
/*uchar 类型不能直接通过cout输出到terminal,ASCII码默认隐藏*/
int m[3][3] = {{0,0,0},{0,0,0},{0,0,0}};
static Mat temp_matrix=Mat(3,3,CV_8UC1,m);
//cout<<matrix<<endl;
temp_matrix.ptr<uchar>(0)[0] = matrix.ptr<uchar>(h_j)[w_i];
temp_matrix.ptr<uchar>(0)[1] = matrix.ptr<uchar>(h_j)[w_i+1];
temp_matrix.ptr<uchar>(0)[2] = matrix.ptr<uchar>(h_j)[w_i+2];
temp_matrix.ptr<uchar>(1)[0] = matrix.ptr<uchar>(h_j+1)[w_i];
temp_matrix.ptr<uchar>(1)[1] = matrix.ptr<uchar>(h_j+1)[w_i+1];
temp_matrix.ptr<uchar>(1)[2] = matrix.ptr<uchar>(h_j+1)[w_i+2];
temp_matrix.ptr<uchar>(2)[0] = matrix.ptr<uchar>(h_j+2)[w_i];
temp_matrix.ptr<uchar>(2)[1] = matrix.ptr<uchar>(h_j+2)[w_i+1];
temp_matrix.ptr<uchar>(2)[2] = matrix.ptr<uchar>(h_j+2)[w_i+2];
//if((int)matrix.ptr<uchar>(h_j)[w_i]>0){
// cout<<"middle:\n"<<temp_matrix<<endl;
// cout<<(int)matrix.ptr<uchar>(h_j)[w_i]<<"\t"<<(int)matrix.ptr<uchar>(h_j)[w_i+1]<<"\t"<<(int)matrix.ptr<uchar>(h_j)[w_i+2]<<"\t"<<(int)matrix.ptr<uchar>(h_j+1)[w_i]<<"\t"<<(int)matrix.ptr<uchar>(h_j+1)[w_i+1]<<"\t"<<(int)matrix.ptr<uchar>(h_j+1)[w_i+2]<<"\t"<<(int)matrix.ptr<uchar>(h_j+2)[w_i]<<"\t"<<(int)matrix.ptr<uchar>(h_j+2)[w_i+1]<<"\t"<<(int)matrix.ptr<uchar>(h_j+2)[w_i+2]<<"\t"<<endl;
// changelabel = true;
//}
return temp_matrix;
}
int sobel_conv2d(Mat matrix1,Mat edge_opt)
{
int gradient = abs(matrix1.ptr<uchar>(0)[0]*edge_opt.ptr<float>(0)[0]
+matrix1.ptr<uchar>(0)[1]*edge_opt.ptr<float>(0)[1]
+matrix1.ptr<uchar>(0)[2]*edge_opt.ptr<float>(0)[2]
+matrix1.ptr<uchar>(1)[0]*edge_opt.ptr<float>(1)[0]
+matrix1.ptr<uchar>(1)[1]*edge_opt.ptr<float>(1)[1]
+matrix1.ptr<uchar>(1)[2]*edge_opt.ptr<float>(1)[2]
+matrix1.ptr<uchar>(2)[0]*edge_opt.ptr<float>(2)[0]
+matrix1.ptr<uchar>(2)[1]*edge_opt.ptr<float>(2)[1]
+matrix1.ptr<uchar>(2)[2]*edge_opt.ptr<float>(2)[2]);
//if(gradient>0)
//{
// cout<<matrix1<<endl;
// cout<<edge_opt<<endl;
// cout<<"in:"<<gradient<<endl;
// changelabel=true;
//}
return gradient;
}
static Mat edge_detect(Mat im, int sobel_thresh)
{
/*开始犯了一个低级错误,edge_opt_Gx,edge_opt_Gy里面存在-1,-2,结果我还用的uchar,傻!!!*/
Mat edge_opt_Gx=(Mat_<float>(3,3)<<-1,0,1,-2,0,2,-1,0,1);
Mat edge_opt_Gy=(Mat_<float>(3,3)<<-1,-2,-1,0,0,0,1,2,1);
Size image_size;
image_size.width = im.cols;
image_size.height = im.rows;
static Mat edge_img=im.clone();
im.copyTo(edge_img);
int max_value=0;
int min_value=0;
for(int w_i = 0; w_i < image_size.width-2; w_i++)
{
for (int h_j = 0; h_j < image_size.height-2; h_j++)
{
//cout<<"im:"<<im.ptr<uchar>(h_j)[w_i]<<"\t";
/*cv::Mat M(3, 3, CV_8U);--会报错Segmentation fault (core dumped)不明白为啥非得先用多维数组初始化矩阵,这种错误一般有3个原因:1--数组访问出界;2--访问到只读内存;3--访问到已释放的变量*/
int m[3][3] = {{0,0,0},{0,0,0},{0,0,0}};
Mat temp_matrix=Mat(3,3,CV_8UC1,m);
//cout<<temp_matrix<<endl;
//cout<<"im:"<<(int)im.at<uchar>(h_j,w_i)<<"\t"<<(int)im.ptr<uchar>(h_j+1)[w_i]<<"\t"<<(int)im.ptr<uchar>(h_j+2)[w_i]<<"\t"<<endl;
temp_matrix = get_temp_matrix(im,h_j,w_i);
//if((int)temp_matrix.ptr<uchar>(0)[0]>0)
//if(changelabel==true)
//{
// cout<<"before:\n"<<temp_matrix<<endl;
//}
Mat temp1_matrix=Mat(3,3,CV_8UC1,m);
temp1_matrix = set_1_fun(temp_matrix);
//if((int)temp1_matrix.ptr<uchar>(0)[0]>0)
if(changelabel==true)
//{
// cout<<"after:\n"<<temp1_matrix<<endl;
// //changelabel=false;
//}
temp_matrix.release();
int Gx = sobel_conv2d(temp1_matrix,edge_opt_Gx);
//if(changelabel==true){
// cout<<"Gx:"<<Gx<<endl;
// changelabel=false;
//}
int Gy = sobel_conv2d(temp1_matrix,edge_opt_Gy);
//if(changelabel==true){
// cout<<"Gy:"<<Gy<<endl;
// changelabel=false;
//}
temp1_matrix.release();
if(Gx+Gy<sobel_thresh)
{
//cout<<"Gx+Gy:"<<Gx+Gy<<endl;
edge_img.ptr<uchar>(h_j+1)[w_i+1]=0;
}
//cout<<"dot result:"<<a<<endl;
}
//cout<<"total w:"<<image_size.width<<"\ttotal h:"<<image_size.height<<endl;
}
cout<<"max:"<<max_value<<"\tmin:"<<min_value<<endl;
return edge_img;
}
int main(void)
{
vector<string> files=getFiles("../chessboard/ori/");
//批处理
//for (int i=0; i<files.size(); i++)
//{
// Mat imageInput = imread("../chessboard/ori/"+files[i]);
//}
Mat imageInput = imread("../chessboard/ori/"+files[0]);
Size image_size;
image_size.width = imageInput.cols;
image_size.height = imageInput.rows;
Mat gray_img;
cvtColor(imageInput, gray_img, CV_RGB2GRAY);
imwrite("gray_img.jpg",gray_img);
Mat binary_img;
threshold(gray_img, binary_img, 50, 255, CV_THRESH_BINARY);
Mat edge_im = binary_img.clone();
edge_im = edge_detect(binary_img,1);
imwrite("edge_img.jpg",edge_im);
imwrite("binary_img.jpg",binary_img);
cout<<"finish!"<<endl;
return 0;
}
重点:
- 对C++变量所处存储区的认识(局部变量存于栈区,static变量存于静态存储区,new分配的变量存于堆区,malloc分配的存于自由存储区,常量存于常量存储区)
- 对于图像(Mat类型)的像素值访问(at方式,ptr指针方式,……)
待检测图像 | 边缘检测结果 |