2018年3月16日 星期五

透視投影(WarpPerspective) 與 仿射投影(WarpAffine) 實作範例代碼(source code)

透視投影(WarpPerspective) 與 仿射投影(WarpAffine) 實作範例代碼(source code)

他們指的是一個影像投射到不同視覺角度上的變化情況

透視投影

  • 是3D的
  • 投影完維持四邊形,直線還是直線但不再平行
可以查看那些鐵軌的圖片,會發現鐵軌越往遠處就會越靠近而不是平行的,儘管他們實際上是平行的,鐵軌的遠方就是透視點。(透視點也是繪圖困難的地方,尤其是人體很吃過往的經驗)
公式
假想有一張圖
把灰色的點固定不動,紅色的點任意你移動,圖片會跟紅點動,可以假想這是一個氣球的皮上面畫有圖像然後你對紅點任意 [移動or縮放] 的的概念。

仿射投影

  • 是2D的
  • 投影完會維持平行四邊形,原本平行的東西還是平行
公式其實與透視投影一樣,取前6個就是第三排Z直接不要了
一般表示方法會 m31=m32=0 m33=1
這樣一來一樣套原本的算法就不需要再除上Z了,式子帶入會被消除。
延續剛剛的概念,現在把紅點刪除一個(或者是說兩個點永遠同步移動)
他們永遠都會是平行四邊形,只是可能出現各種形狀

參考代碼

下面是程式核心的轉換代碼
轉換有分兩種,同一個矩陣可以是
原圖座標轉換到新圖座標,也就是一般看到的公式
另一種反轉是透過計算 反矩陣(逆矩陣) 而來的,詳細可以參考
https://www.wikiwand.com/zh-tw/%E9%80%86%E7%9F%A9%E9%98%B5
只是把它反過來而已,程式中我已經幫你寫上了。
有一點要注意的是,轉換過去再轉換回來會有一些誤差。
// 輸入 dst 座標, 反轉 scr 輸出.
void WarpPerspective_CoorTranfer_Inve(const vector<double>& HomogMat, double& x, double& y) {
    const double* H = HomogMat.data();
    const double i=x, j=y;

    x = (H[2] - H[8]*i) * (H[4] - H[7]*j) - 
        (H[1] - H[7]*i) * (H[5] - H[8]*j);
    y = (H[0] - H[6]*i) * (H[5] - H[8]*j) - 
        (H[2] - H[8]*i) * (H[3] - H[6]*j);

    double z = (H[1] - H[7]*i) * (H[3] - H[6]*j) - 
        (H[0] - H[6]*i) * (H[4] - H[7]*j);

    x /= z;
    y /= z;
}
// 輸入 scr 座標, 轉換 dst 輸出.
void WarpPerspective_CoorTranfer(const vector<double>& HomogMat, double& x, double& y) {
    const double* H = HomogMat.data();
    const double i=x, j=y;

    x = H[0]*i + H[1]*y +H[2];
    y = H[3]*i + H[4]*y +H[5];
    double z = H[6]*i + H[7]*y +H[8];

    x /= z;
    y /= z;

    //x=round(x);
    //y=round(y);
}

參考

2018年3月14日 星期三

OpenCV Mat 讀取數值錯誤,如何讀出正確數值

OpenCV Mat 讀取數值錯誤,如何讀出正確數值

在做仿射轉換的時候發現讀出來的數值都怪怪的,找了很久,後來才想到應該是要用 double,下面是讀取的範例。
    //選定幾何轉換前後相對的三個點
    Point2f srcTri[3];
    srcTri[0] = Point2f(0, 0);
    srcTri[1] = Point2f(10, 0);
    srcTri[2] = Point2f(0, 10);

    Point2f dstTri[3];
    dstTri[0] = Point2f(10, 10);
    dstTri[1] = Point2f(20, 10);
    dstTri[2] = Point2f(10, 20);

    Mat warp_mat = getAffineTransform(srcTri, dstTri);

    cout << warp_mat << endl;
    cout << "=========================" << endl;

    for(size_t j = 0; j < warp_mat.rows; j++) {
        for(size_t i = 0; i < warp_mat.cols; i++) {
            cout << warp_mat.at<float>(j, i) << ", "; // 錯誤
            //cout << warp_mat.at<double>(j, i) << ", "; // 正確
        } cout << endl;
    } cout << endl;

Win7 boot Error Code: 0xc0000225 repair 修復方法

Win7 boot Error Code: 0xc0000225 repair 修復方法

delete all partition,
then rebuild partition and install windows.


可以見到 bcd 選單基本上開機檔都ok沒問題了~
不用去修復這些了,會造成這麼情況就算重灌也沒用
我確實也嘗試過修復,以及多次重新安裝,就是都一樣
後來找到的原因好像是因為分割區的問題,刪除所有磁區然後重新切割再安裝即可~
我這顆硬碟有點問題,有跳C6的黃燈,所以如果你有見到這個錯誤,很有可能是硬碟的問題導致的,分割表那邊的磁軌正好出問題,檢查一下比較保險~

2018年3月13日 星期二

實作代碼 如何切適當的分函式功能

實作代碼 如何切適當的分函式功能

寫了一個大專案之後整理的心得,隨著經驗的累積還會再更新。
寫程式的風格或許沒有最優解,有的只是不斷地採坑不斷地總結。
如果正好這一個風格適合多數人,而且確實效率好,那就是一份好方法。
這一份方法可以稱為高頻小套路,是讓一個新手高效率成長的最優解。

2018.03.13

一個好的流程架構最好的開發方法,先用別人的函式庫如OpenCV完成
然後開始拆分他的函式拆成可以理解的大功能ABC,然後分別單獨實作ABC
大功能ABC具有的特性是
    1. 各個都是大量運算
    2. 彼此之間傳遞的資料項目簡單,最好就int
(要找到大運算中間的休息點傳遞基本數值以便丟棄大物件,讓他在func內結束減少干擾)
    3. 到哪裡都可以運行
        然後這些ABD中的A裡面又有 abc 小項目

        abc小項目中需要有下面的特性
        1. 有明確的目標就是要幹嘛
        2. 只能完成一件事情
        3. abc組合起來是流程圖
        4. 每個都是可公開的 ADT
        5. 只能用物件當引數
        6. 可以容納,不知道該怎麼處理的髒代碼

            然後這些 abc 其中的 a 又有123小項目
            123 需要有下面特性
            1. 只為了做一件小事,代碼長度不超過1個 1080P 螢幕
            3. 避免使用物件當引數,拆解成基本型態
            4. 到哪裡都可以運行

2018年3月12日 星期一

opencv 特徵點匹配 ORB、SURF、SIFT 以及 RANSAC 過濾的範例代碼

opencv 特徵點匹配 ORB、SURF、SIFT 以及 RANSAC 過濾的範例代碼

void sift1(string name1, string name2){
    Mat img_1 = imread(name1, CV_LOAD_IMAGE_GRAYSCALE);
    Mat img_2 = imread(name2, CV_LOAD_IMAGE_GRAYSCALE);
    Mat img_matches;
    Mat img_test;

    if(!img_1.data || !img_2.data){
        cout << "opencv error" << endl;
        return;
    }

    // cv::Ptr<Feature2D> f2d = xfeatures2d::SIFT::create();
    // cv::Ptr<Feature2D> f2d = xfeatures2d::SURF::create();
    cv::Ptr<Feature2D> f2d = ORB::create();

    //-- Step 1: Detect the keypoints:
    std::vector<KeyPoint> keypoints_1, keypoints_2;
    f2d->detect(img_1, keypoints_1);
    f2d->detect(img_2, keypoints_2);

    img_test = img_1;
    drawKeypoints(img_1, keypoints_1, img_test, Scalar::all(-1));
    imshow("Keypoints", img_test);

    //-- Step 2: Calculate descriptors (feature vectors)    
    Mat descriptors_1, descriptors_2;
    f2d->compute(img_1, keypoints_1, descriptors_1);
    f2d->compute(img_2, keypoints_2, descriptors_2);

    //-- Step 3: Matching descriptor vectors using BFMatcher :
    BFMatcher matcher;
    std::vector< DMatch > matches;
    matcher.match(descriptors_1, descriptors_2, matches);
    drawMatches(img_1, keypoints_1, img_2, keypoints_2,
        matches, img_matches, Scalar::all(-1), Scalar::all(-1),
    std::vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS);
    imshow("Matches", img_matches);

    //-- Quick calculation of max and min distances between keypoints
    double max_dist = 0; double min_dist = 100;
    for(int i = 0; i < descriptors_1.rows; i++){
        double dist = matches[i].distance;
        if(dist < min_dist) min_dist = dist;
        if(dist > max_dist) max_dist = dist;
    }
    printf("-- Max dist : %f \n", max_dist);
    printf("-- Min dist : %f \n", min_dist);
    //-- Draw only "good" matches (i.e. whose distance is less than 3*min_dist )
    std::vector< DMatch > good_matches;
    for(int i = 0; i < descriptors_1.rows; i++){
        if(matches[i].distance < 3 * min_dist)
            good_matches.push_back(matches[i]);
    }
    drawMatches(img_1, keypoints_1, img_2, keypoints_2,
        good_matches, img_matches, Scalar::all(-1), Scalar::all(-1),
        std::vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS);
    imshow("Good Matches", img_matches);

    vector<DMatch>& Input_matches = matches; // good_matches, matches
    // get feat point
    vector<Point2f> featPoint1;
    vector<Point2f> featPoint2;
    for(size_t i = 0; i < Input_matches.size(); i++){
        //-- Get the keypoints from the good matches
        featPoint1.push_back(keypoints_1[Input_matches[i].queryIdx].pt);
        featPoint2.push_back(keypoints_2[Input_matches[i].trainIdx].pt);
    }
    // get Homography and RANSAC mask
    vector<char> RANSAC_mask;
    Mat Hog = findHomography(featPoint1, featPoint2, RANSAC, 3, RANSAC_mask, 2000, 0.995);
    drawMatches(img_1, keypoints_1, img_2, keypoints_2,
        Input_matches, img_matches, Scalar::all(-1), Scalar::all(-1),
        RANSAC_mask, DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS);
    imshow("RANSAC Matches", img_matches);

    waitKey(0);
}

2018年3月10日 星期六

Win10 ATI HD4850 4870 driver 正確運作 CCC 軟體

Win10 ATI HD4850 4870 driver 正確運作 CCC 軟體

先看結果 (右下角有當前時間)
AMD的官方已經直接表名說不支持不能用了,不過實際測試之後還是可以使用。
測試的系統是 Windwos10 1709,顯示卡有 HD4870 HD4855 HD4350 等三張。

安裝開始

要分開裝驅動與 catalyst control center 軟體

下載

要下載舊版的來用
目標下載 13.1 來使用
下載下來要先安裝
這個會先解壓縮到C曹的這個位置,先解壓縮(按上圖Install)
然後會跳出安裝選單如下圖,先不要按,重要的是目前已取得檔案等一下會用到。
到上圖這個畫面就先停著不要動

手動安裝驅動

打開工作管理員,快捷鍵是先按 Win+X 然後再按 M
選到剛剛的位置 (下面是預設)
C:\AMD\Support\13-1-legacy_vista_win7_win8_64_dd_ccc\Packages\Drivers\Display\W86A_INF
選中 C7 開頭的這個
然後就可以安裝了,安裝完成之後解析度就可以正常條了
要確認有沒有安裝可以查看驅動程式日期,13.1內附的驅動日期是2012.11,微軟提供的是2015版本的,要驅動CCC必須使用CCC內附的版本才可以。

CCC 驅動安裝

必須先安裝完驅動才可以,再來跳回來剛剛的CCC安裝介面可以按下一步了。
如果要開CCC,那驅動就要裝CCC附贈的同一個驅動版本。
這裡要選自訂然後取消驅動的打勾(因為剛剛已經安裝了)

(備註:我不是在同一台電腦做的,這台沒安裝卡,這裡才會不能取消打勾)
然後安裝完畢之後可能還會看不到,要重新啟動之後 CCC 開起來就可以調整細部選項了
比如說接上 HDMI 之後螢幕內縮編編有黑框,可以把縮放調為 0 就沒黑邊了
或者是接上 HDMI 之後顏色怪怪的偏白,也是驅動裡面調成全彩 RGB 就好了
經過測試後發現最新可安裝的版本為 13.4 版本,這個也可以順利驅動+開啟CCC,不過介面是英文版的。

2018年3月9日 星期五

Win10 一直自動清理縮圖,要重跑縮圖

Win10 一直自動清理縮圖,要重跑縮圖

貌似是更新到 1709 才這樣,我不確定是升級上還得bug還是全新安裝也會這樣,總而言之好像還蠻多人的,解決辦法只能停用這個功能。
1709之後多了自動清理緩存的功能,不過實際上如果SSD容量足夠並不建議時常清理,半年清理個一次就差不多了。

自動清理的設定位置

位置在 儲存空間 內,你可以直接在開始搜尋 儲存空間 就可以看到他
這個東西會自動清理,但是我已經將它關閉了,他還是不正常作用,時不時就給我清理一下,實在很惱人。
工作排程DiskCleanupSilentCleanup 強制關閉這個功能就會好了。
工作排程可以在開始欄打字搜尋找到。
找到他之後把它關閉吧,之後就不會再來煩你了~