C++ 影像處理如何畫線與畫箭頭
代碼關鍵函式要用點斜式,然後用for迴圈去跑x軸或y軸,跑完那一條線
struct ImgRaw{
int width;
int height;
vector<unsigned char> raw_img;
};
void drawLine_p(ImgRaw& img, int y, int x, int y2, int x2, float val) {
// 兩點之間的距離差
float dx = static_cast<float>(x2-x);
float dy = static_cast<float>(y2-y);
// 以Y軸為主
float sita=fastAtan2f(dy, dx);
if (sita>45 and sita<135 or sita>225 and sita<315) {
float slopeY = dx/dy; // 斜率
for (int i = 0; i < abs(dy); i++) {
int iFix = dy>0? i:-i;
int currPos = static_cast<int>(iFix*slopeY+.5f + 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;
}
img.raw_img[distY*img.width + distX] = static_cast<unsigned char>(val);
}
}
// 以X軸為主
else {
float slopeX = dy/dx; // 斜率
for (int i = 0; i < abs(dx); i++) {
int iFix = dx>0? i:-i;
int currPos = static_cast<int>(iFix*slopeX+.5 + y);
int distX = x+iFix;
int distY = currPos;
if (distX<0 or distX>=(int)img.width or distY<0 or distY>=(int)img.height) {
return;
}
img.raw_img[distY*img.width + distX] = (unsigned char)val;
}
}
}
然後角度的不一樣比如說45~90度跑Y軸會比較好,線連得比較密,如果是0~45度則是跑X軸比較好,才不會出現斷線。
角度的判斷計算使用。
float sita = fastAtan2f(dy, dx);
- ImgRaw帶有圖像資訊、長、寬
- fastAtan2f是從OpenCV複製出來的可以參考站內文這裡
接下來有了直線之後就是寫一個,輸入角度與長度的函式,簡單來說就是算出頭尾的位置然後帶入剛剛的函式畫線。
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條線,帶入剛剛的給點給角度的函式畫出箭頭
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
沒有留言:
張貼留言