編程語言學習(隨機數組,插入、冒泡、選擇排序,Qt)

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指針方式,……)
待檢測圖像 邊緣檢測結果

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章