2017年10月4日 星期三

C / C++ 影像處理如何畫線與畫箭頭

C++ 影像處理如何畫線與畫箭頭

代碼關鍵函式要用點斜式,然後用for迴圈去跑x軸或y軸,跑完那一條線
float slopeY = dx/dy; // 斜率
for (int i = 0; i < abs(dy); i++) {
    int iFix = dy>0? i:-i;
    int currPos = iFix*slopeY + x;
    int distX = currPos;
    int distY = y+iFix;
    if (distX<0 or distX>=(int)img.width or 
        distY<0 or distY>=(int)img.height)
    {
        return;
    }
    size_t posi = distY*img.width + distX;
    img.raw_img[posi*3 + 0] = 255;
    img.raw_img[posi*3 + 1] = 0;
    img.raw_img[posi*3 + 2] = 0;
}
然後角度的不一樣比如說45~90度跑Y軸會比較好,線連得比較密,如果是0~45度則是跑X軸比較好,才不會出現斷線。
角度的判斷計算使用。
float sita = fastAtan2f(dy, dx);
  • ImgRaw帶有圖像資訊、長、寬
  • fastAtan2f是從OpenCV複製出來的可以參考站內文這裡
接下來有了直線之後就是寫一個,輸入角度與長度的函式,簡單來說就是算出頭尾的位置然後帶入剛剛的函式畫線。
static void drawLineRGB_s(ImgRaw& img, int y, int x, float line_len, float sg) {
        // 檢查
        if (line_len <= 0) { return; }
        // 算頭尾
        int x2 = x + line_len*cos(sg * M_PI/180);
        int y2 = y + line_len*sin(sg * M_PI/180);
        // 畫線
        drawLineRGB_p(img, y, x, y2, x2);
    }
再來箭頭就只是多話2條線,帶入剛剛的給點給角度的函式畫出箭頭
static void draw_arrowRGB(ImgRaw& img, int y, int x, float line_len, float sg) {
        // 檢查
        if (line_len <= 0) { return; }
        // 算頭尾
        int x2 = x + line_len*cos(sg * M_PI/180);
        int y2 = y + line_len*sin(sg * M_PI/180);
        // 畫線
        drawLineRGB_p(img, y, x, y2, x2);
        // 畫頭
        drawLineRGB_s(img, y2, x2, 10, sg-150);
        drawLineRGB_s(img, y2, x2, 10, sg+150);
    }


如何使用

drawLine有兩個,一個是給定兩個點,把他們連起來,另一個是給定原點, 長度, 角度,也就是給極值的方式畫線。
    ImgRaw img_lineRGB(1280, 720);
    for (size_t i = 0; i < 36; i++) {
        Draw::draw_arrowRGB(img_lineRGB, 200, 200, 100.f*sqrt(2), i*10);
    } img_lineRGB.bmp("lineRGB.bmp");
ImgRaw 做的事情很簡單只是開一個 vector(1280*720*3) 然後儲存他的長1280和寬720
畫一圈的箭頭

原理

主要是利用斜率去算的,假設有兩個點,分別是 (0, 0) 與 (40,50) 斜率的公式,其中b是偏移量暫時不管她。
y=ax+b;
斜率就只是相減而已
dy=50-0;
dx=40-0;

m=dy/dx;
既然已知斜率那就用for迴圈去跑x的範圍 0~40 就可以得出y的位置了
不過這會遇到一個問題是當直線是上下的時候 for 迴圈跑的次數是0畫不出線,其次可以發現這種畫法當線條比較偏上的時候,45~135度的範圍會明顯斷線的感覺,因此這時候要變成以y為主,for迴圈去跑y反向計算出x。
這樣就可以畫出上圖比較好看一些的線條了。


範例程式

完整的程式參考:https://goo.gl/rAJLjH

沒有留言:

張貼留言