1. 程式人生 > >【不斷更新貼】總結程式設計的技巧、語法等,需要多敲程式碼、記憶掌握

【不斷更新貼】總結程式設計的技巧、語法等,需要多敲程式碼、記憶掌握

1. void DrawRectangle( cv::Mat& img, cv::Rect  box )
{
cv::rectangle(img,box.tl(),box.br(),cv::Scalar(g_rng.uniform(0, 255), g_rng.uniform(0,255), g_rng.uniform(0,255)));//隨機顏色

}

注意: Rect型別可以直接通過Rect.tl()  Rect.br() 獲取矩形的左上角、右下角座標 

檢視原始碼的定義:! the top-left corner
                         //Point_<_Tp> tl() const;
                        //! the bottom-right corner
                          //Point_<_Tp> br() const;

2.隨機顏色: RNG   g_rng(12345);

cv::rectangle(img,box.tl(),box.br(),cv::Scalar(g_rng.uniform(0, 255), g_rng.uniform(0,255), g_rng.uniform(0,255)));//隨機顏色

檢視RNG原始碼:

/! returns uniformly distributed double-precision floating-point random number from [a,b) range
//double uniform(double a, double b);

3.深度複製MAT

     (1)Mat srcImage(600, 800,CV_8UC3), tempImage;
        srcImage.copyTo(tempImage);

      (2)Mat tempImage=srcImage.clone()

4.定義ROI區域

   Mat image=imread("~~~~");

  Mat imageROI=image(Rect(300,230,logo.cols,logo.rows));

5. convertScaleAbs  

使用線性變換轉換輸入陣列元素成8位無符號整型。  convertScaleAbs( normImage, scaledImage );//將歸一化後的圖線性變換成8位無符號整型 

void cvConvertScaleAbs( const CvArr* src, CvArr* dst, double scale=1, double shift=0 );

#define cvCvtScaleAbs cvConvertScaleAbs

其中引數含義:

src : 原陣列

dst :輸出陣列 (深度為 8u).

scale :比例因子.

shift :原陣列元素按比例縮放後新增的值。

函式 cvConvertScaleAbs 與前一函式是相同的,但它是存貯變換結果的絕對值:

dst(I)=abs(src(I)*scale + (shift,shift,...))

函式只支援目標數陣列的深度為 8u (8-bit 無符號) , 對於別的型別函式仿效於cvConvertScale 和 cvAbs 函式的聯合 。

6.normalize

// 歸一化與轉換
normalize( dstImage, normImage, 0, 255, NORM_MINMAX, CV_32FC1, Mat() );

函式原型:

    void normalize(InputArray src,OutputArray dst, double alpha=1, doublebeta=0, int norm_type=NORM_L2, int dtype=-1, InputArray mask=noArray() )

    該函式歸一化輸入陣列使它的範數或者數值範圍在一定的範圍內。

Parameters:

src

    輸入陣列

dst

    輸出陣列,支援原地運算

alpha

    range normalization模式的最小值

beta

    range normalization模式的最大值,不用於norm normalization(範數歸一化)模式。

normType

    歸一化的型別,可以有以下的取值:

    NORM_MINMAX:陣列的數值被平移或縮放到一個指定的範圍,線性歸一化,一般較常用。

    NORM_INF: 此型別的定義沒有查到,根據OpenCV 1的對應項,可能是歸一化陣列的C-範數(絕對值的最大值)

    NORM_L1 :  歸一化陣列的L1-範數(絕對值的和)

    NORM_L2: 歸一化陣列的(歐幾里德)L2-範數

dtype

    dtype為負數時,輸出陣列的type與輸入陣列的type相同;

否則,輸出陣列與輸入陣列只是通道數相同,而tpye=CV_MAT_DEPTH(dtype).

mask

    操作掩膜,用於指示函式是否僅僅對指定的元素進行操作。

歸一化公式:

1、線性函式轉換,表示式如下:(對應NORM_MINMAX)

ifmask(i,j)!=0

    dst(i,j)=(src(i,j)-min(src))*(b‘-a‘)/(max(src)-min(src))+ a‘

else

     dst(i,j)=src(i,j)

    其中b‘=MAX(a,b), a‘=MIN(a,b);

2. 當norm_type!=CV_MINMAX:

ifmask(i,j)!=0

    dst(i,j)=src(i,j)*a/norm (src,norm_type,mask)

else

    dst(i,j)=src(i,j)

    其中,函式norm的功能是計算norm(範數)的絕對值

Thefunctions norm calculate an absolute norm of src1 (when there is no src2 ):

技術分享

7. 建立同樣大小、形狀的影象

    (1)Mat imgIn=imread(" XXXXX");

    (2)Mat imgOut(newHeight, newWidth, imgIn.type());         // Mat resultImg;  XXXXXXXX;             resultImg.create(newHeight, newWidth, imgIn.type()); 

這兩者是有區別的  ,Mat imgOut(newHeight, newWidth, imgIn.type());   僅僅是在定義的時候宣告建立  而  resultImg.create(newHeight, newWidth, imgIn.type()); 是在先宣告,然後在函式中建立

     (3)有待補充

8. 訪問畫素的幾種方法

 (1). for( i=0;i<DstHeight;i++)
{ uchar *dst_data=OutImg.ptr<uchar>(i);

                 for(j=0;j<DstWidth;j++)

                 dst_data[j]=.....

  (2)  for( i=0;i<DstHeight;i++)
for(j=0;j<DstWidth;j++)
{
if(img.channels()==3)
{
out1.at<Vec3b>(i,j)=Vec3b(255,0,0);
}
else if(img.channels()==1)
{
out1.at<uchar>(i,j)=255;
}

                      if(img.channels()==3)
{
out1.at<Vec3b>(i,j)=img.at<Vec3b>(i1,j1);//(j1,i1);
}
else if(img.channels()==1)
{
out1.at<uchar>(i,j)=img.at<uchar>(i1,j1);

9.注意程式碼中新增檢查低階錯誤的程式碼 說不定哪天就會犯錯誤  

今天就是的,至少檢查了1個小時,還很鬱悶

Mat SrcImg=imread("C:\\Users\\Administrator\\Desktop\\工作\\testp\\o1.jpg");

if(!SrcImg.data)

cout<<"讀取圖片錯誤\n";

//上面的o1.jpg   應該是01.jpg   一開始沒有新增 就是記憶體報錯 檢查啊檢查~~~~

10.  自己定義核函式膨脹腐蝕   

   Mat kernel=getStructuringElement(MORPH_CROSS,Size(3,3),Point(-1,-1));
dilate(src,dst,kernel);

11. 結合輪廓篩選給出容器類的刪除注意方式

    vector<vector<Point> >::iterator itc= contours.begin();
    vector<RotatedRect> rects;
    //Remove patch that are no inside limits of aspect ratio and area.    
    while (itc!=contours.end()) 
{
        //Create bounding rect of object
        RotatedRect mr= minAreaRect(Mat(*itc));
        if( !verifySizes(mr)){
            itc= contours.erase(itc);  //注意這裡刪除容器會導致迭代器的變化  這裡刪除itc自動跳到下一個元素上 所以就不需要++itc
        }else{
            ++itc;
            rects.push_back(mr);
        }
    }

12. 通過流 來寫字串形

#include<iostream>
#include <sstream>
using namespace std;
void main()
{
string filename="come_on";
for(int i=0;i<8;i++)
{
stringstream ss(stringstream::in | stringstream::out);
ss << "tmp/" << filename << "_" << i << ".jpg";
imwrite(ss.str(), img);
}
}

13.讀取list路徑下的圖片 resize大小 並另存 圖片名和之前一樣


ifstream infile("/media/d/Yang/project_8-9/data/mark1/list.txt");
string str;
while(infile>>str)  //str=   /media/d/Yang/project_8-9/data/mark1/chejiahao_str_4654.jpg
{
    string save_pre="/media/d/Yang/project_8-9/data/mark/";
    int pos=str.find_last_of("/");
    string img_name=str.substr(pos+1,str.size()-1-pos);
    string save_path=save_pre+img_name;
    Mat img=imread(str);
    Mat img_r;
    resize(img,img_r,Size(600,150));
    imwrite(save_path,img_r);

}

14 stringstream 清空資料

  stringstream ss;

 ImgName_Label+=ss.str();     
                 ss.str("");  //這個才是清空資料 注意 有點奇葩
                 ss.clear(); //只能重置其狀態標誌位

15 HSV顯示偏紅的問題

http://www.xuebuyuan.com/1681149.html  可以看這裡一張貓的圖片,因為我把hsv圖show出來看,很是納悶,為什麼就偏紅呢,叫來txy,gkj來看,我說這個亮的地方hsv就偏紅,好奇怪,txy說imshow就是以bgr形式顯示的,BGR--HSV  HSV的V對應著R 所有亮的地方顯紅 不管什麼HSV,opencv就以bgr來解析

16 vector<> 固定大小並初始化

vector<bool> v_b;
     v_b.resize(20,false);
// vv_flg.resize(tab_unit.size(),vector<bool>());

17  影象roi區域全部置為255

    Mat m_roi=img_out(rt_aim);
    m_roi.setTo(Scalar(255,255,255));

18 訓練模型積累

剛開始訓練模型的時候可以先把學習率調大,一般是乘以10.目的是更快的達到區域性最小,當發現loss降的很小或者震盪的時候再把學習率調小;

一定要看影象的寬高比.因為網路訓練都會壓縮到統一尺寸,比如300*300,150*150.最近遇到的就是,訓打鉤和橫線專案,它本來的尺寸一般是150*36的..g老師的那個lenet分類網路是28*28的.訓練出來的模型√前面的勾準確度不高,他把壓縮28*28發現√前面的勾基本看不到了. 還有就是訓練檢驗表上面車牌定位,我根據leftroi的x就上下擴了,左右還是原圖寬,這樣確保車牌號在裡面,截下來大概是1600*230的,然後和文字keymsg一起訓練,它的這樣網路是150*150的,訓出來的模型車牌定位不是那麼準確,li老師訓練發現loss維持在3點多降不下去了..然後把這批資料拿去,發現loss可以降低到1點多..然後分析就是壓縮到150*150.車牌特徵就都沒了.

2018年05月10日 訓練segnet儀表盤,就是指標還有黃色綠色紅色區域 ,用的是訓練cjh的segnet網路訓的,然後標的資料我就把標的彩圖標錯的資料刪了,然後再360隨機旋轉訓練的.準確度就92左右上不去,雖然大體能出來,但是前向跑出來的結果很毛躁,.Glaoshi要訓gw的自動標示,準確放一起訓. 他很細心,他說訓練資料很重要,我看他把標好的資料都是放到標註工具裡面一張張的看的不對的再自己修改.我把我的資料共享給他,他看到原始資料有的很髒,他說你這個都放進去啊,然後1000多張他一個個看刪了100多張看不清的...然後旋轉,他說旋轉45°會空出很多黑背景...圖片都是256*256的可以旋轉上下左右,這樣就不會空出黑背景,然後小角度再旋轉幾個,不要隨機角度.寫個陣列,恩,確實! 然後我就旋轉90,180,270,+-2,+-5.恩,資料層完畢,訓練的時候我一味的把學習率調到0.0001,因為之前訓練也是這樣,以為越小越好,但是Glaoshi發現一個規律就是loss在0.5-1之間的時候學習率為0.01訓練會能提高準確度,果真,如此整下來精度能提高到95%,訓練好久再把學習率調低一點,效果也蠻好....學習了

19 過濾出豎線橫線

    int tmp = bi.cols /50;
    cout<<"tmp_dilate="<<tmp<<endl;
    Mat horizontalStructure_ = getStructuringElement(MORPH_RECT, Size(tmp,1));
    dilate(bii, bi_dilate_heng, horizontalStructure_, Point(-1, -1));   //橫向膨脹,使得豎線很寬 後續再用開運算可以方便的過濾出很胖的豎線

  Mat m_horizon_open,m_vertic_open;
    vertic_hbd(bi_dilate_heng,m_vertic_open);

bool vertic_hbd(cv::Mat &bw2, cv::Mat &vertical)
{
    vertical = bw2.clone();
    int scale = 4;

    int verticalsize = vertical.rows / scale;

    Mat verticalStructure = getStructuringElement(MORPH_RECT, Size( 1,verticalsize));
    erode(vertical, vertical, verticalStructure, Point(-1, -1));
    dilate(vertical, vertical, verticalStructure, Point(-1, -1));
    return true;
}

20: C++ string的replace小函式

string str_replace(const string &str, const string &str_find, const string &str_replacee)
{
    string str_tmp=str;
    size_t pos = str_tmp.find(str_find);
    while (pos != string::npos)
    {
        str_tmp.replace(pos, str_find.length(), str_replacee);
        pos = str_tmp.find(str_find);
    }
    return str_tmp;
}

20_1: 修改-C++ string的replace小函式

上面的程式碼的問題是比如我 nice_1.png 要把"." 換成".cut" 就會死迴圈 , 因為你替換的str_replace裡面包含你的str_find字元,然後替換好了再迴圈檢查的時候發現還有就會陷入死迴圈,下面是改進的

string str_replace(const string &str,const string &str_find,const string &str_replacee)
{
    string str_tmp=str;
    size_t pos = str_tmp.find(str_find);
    while (pos != string::npos)
    {
        str_tmp.replace(pos, str_find.length(), str_replacee);

        size_t pos_t=pos+str_replacee.length();
        string str_sub=str_tmp.substr(pos_t,str_tmp.length()-pos_t);

        size_t pos_tt=str_sub.find(str_find);
        if(string::npos != pos_tt)
        {
            pos =pos_t + str_sub.find(str_find);
        }else
        {
            pos=string::npos;
        }

    }
    return str_tmp;
}

21  用sort的比較函式不能帶等於號,只能是>or<

static bool Cmp_rt_width_descend(const Rect &r_1,const Rect &r_2)
 {
-    return (r_1.width>=r_2.width);
+    return (r_1.width > r_2.width);
}
bool get_line(vector<Rect>&v_r_in,int up,int down ,int num_back,vector<Rect>&v_r_out)
{
    vector<Rect>v_r_tmp;
    for(int i=0;i<v_r_in.size();i++)
    {
        Rect rt=v_r_in[i];
        if(rt.y>=(up+5) && rt.y<=(down-5))
        {
            v_r_tmp.push_back(rt);
        }
    }

    sort(v_r_tmp.begin(),v_r_tmp.end(),Cmp_rt_width_descend);

    if(1 == num_back && v_r_tmp.size()>=1)
    {
        v_r_out.push_back(v_r_tmp[0]);
    }else if(2 == num_back && v_r_tmp.size()>=2)
    {
        v_r_out.push_back(v_r_tmp[0]);
        v_r_out.push_back(v_r_tmp[1]);
    }else
        return false;

    return true;
}

這裡是解決檢驗表奔潰問題,除錯發現各個變數數值並沒有異常,但是程式返回的時候就是奔潰,在慢慢除錯,發現v_r_tmp的值居然經過sort排序後會改變!!!!難以置信!!!然後各種嘗試,加const啊,還是有問題,然後把等於號去掉,發現沒問題了...

網上的解釋:https://blog.csdn.net/xiyuan1223/article/details/70245197

不知你是否直覺上也會覺得這段程式碼沒什麼問題,但是這段程式碼執行後會core dump。檢視core檔案可以看到記憶體裡的棧被寫壞了,這說明sort呼叫導致了記憶體越界訪問,在這麼少的程式碼行下,不難判定應該是comp函式實現可能不符合c++標準庫的某種規則(C++ STL是基於concept的設計和實現)。
comp函式應該怎麼寫
帶著這個疑問我去查了下c++ stl手冊(http://www.cplusplus.com/reference/algorithm/sort/),發現sort函式對於comp函式還真有一個特殊的要求,叫做“Strict Weak Ordering”。什麼意思呢,它大概可以這麼解釋:如果一個comp函式要滿足“Strict Weak Ordering”,意味著它應該滿足如下特徵(更多細節可以參見SGI版實現相關描述http://www.sgi.com/tech/stl/StrictWeakOrdering.html):
(a) 反自反性:也即comp(x, x)必須是false
(b) 非對稱性:也即如果comp(x, y)和comp(y, x)的結果必然相反
(c) 可傳遞性:也即如果comp(x, y)為true,comp(y, z)為true,那麼comp(x, z)必然為true

這麼看到,示例程式碼的comp定義明顯違反了(a)(b)兩條,所以sort使用它時就可能工作不正常。解決辦法也很簡單,去掉那個“=”,再對照下”Strict Weak Ordering”的定義,應該是滿足了的。

22.  linux 命令---從圖片中拷貝不是00結尾的金額

    cp `ls | grep -v .00.jpg` ../new_file/ 
            
            /new/2017070614364732010017464834_240000.00.jpg
            /new/2017070617364332010017473881_119840.06.jpg
            /new/2017070617344732010017473861_119840.92.jpg
            /new/2017070614371432010017465222_119900.00.jpg
            /new/2017070617304332010017473841_119840.02.jpg
            /new/2017070614374632010017465220_128800.00.jpg
            /new/2017070614382132010017471841_236800.00.jpg
            /new/2017070614382232010017465219_229900.00.jpg
            /new/2017070615535832010017470706_211200.00.jpg
            /new/2017070616382932010017467843_122300.96.jpg
            /new/2017070617324732010017473883_109907.58.jpg
            /new/2017070616383432010017472801_46800.45.jpg
            /new/2017070616435332010017473147_196800.78.jpg

試了下,中間的 ls | grep -v .00.jpg 就會顯示不是00結尾的圖片名字

2018年09月18日14:45:41,我又要用到這條命令,需求是在一個資料夾複製沒有名字rot的圖片,報錯啊報錯:cp: 無法獲取'ls | grep -v rot' 的檔案狀態(stat): 沒有那個檔案或目錄,可是我用 ls | grep -v rot,是可以顯示不帶rot的圖片名字的。後來,讓c哥來看,他翻了他的筆記,用“~”這個,原來:不是單引號,而是鍵盤上波浪號這個, `ls | grep -v rot`    ` `與‘’區分,他說` `這裡面的語句代表命令

23  size_t 形引起的bug

    for(int i=0;i<v_diff.size()-1;i++) // for(int i=0;i<(int)v_diff.size()-1;i++)
    {
        int a=v_diff[i];
        int b=v_diff[i+1];
    }

按照上面寫是錯誤的,除錯發現vector<int>v_diff 本身size就是0,按理說0-1=-1,for迴圈就不會進來,但是它確實進入for迴圈了,原來vector<>的size()屬性是size_t型的,size_t 型別的值時要小心。這是無符號值,就是如果是負數,而它標示的範圍是非負數,就會是的負數當成正數,值就會很大,正確的用法應該如後面註釋,把size()強制型別轉化為int型

24 計算圖片中非0畫素個數

// 非零元素個數    
    int nonZerosNum = countNonZero(img); // me為輸入矩陣或影象    

25. getStructuringElement腐蝕核引數必須是確保是奇數  X/2*2+1

bool My_open(Mat &img_, Mat &img_open)
{
    img_open = img_.clone();
    int scale = 2;

    int horizoncalsize = img_open.cols / scale;
    horizoncalsize=horizoncalsize/2 * 2+1;

    Mat verticalStructure = getStructuringElement(MORPH_RECT, Size( horizoncalsize,1));
    erode(img_open, img_open, verticalStructure, Point(-1, -1));
    dilate(img_open, img_open, verticalStructure, Point(-1, -1));
    return true;
}

26 霍夫line

lines = cvHoughLines2(canny, stor, CV_HOUGH_PROBABILISTIC, 1, CV_PI / 180, 80, 200, 30); 
引數中的200是指要找的直線長度要在200個畫素以上; 
引數中的30指的是兩條在同一直線上的線段,如果相隔不到30,則把它們連起來 
*/  

27 cmake-gui 編譯步驟

先選擇原始碼再選澤build目錄,再點生成,當然其中有些東西要勾選的,比如cmake_install_prefix是安裝位置.然後完了之後在build資料夾敲 make  之後敲make install