开始我在原图上标记并且捕获坐标直接修改并刷新,会有flicker现象出现,影响使用。于是将画图和持久化入图片文件分离。
用屏幕画线的MoveTo(CPoint),lineTo(CPoint)方式跟踪鼠标显示连续轨迹,不会flicker。但是分离了就要记录到buffer里,
以便之后对文件的持久化。这里将鼠标滑过点放入vector<CPoint>中,以此为buffer等待持久化。
void CiHairSegView::drawPoint(CPoint point,bool color){ CiHairSegDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); if (!pDoc) return; if (NULL==pDoc->m_image) { AfxMessageBox("Please load image first"); return; } CPoint tmp = translate(point); if (tmp.x>0&&tmp.x<picWidth &&tmp.y>0&&tmp.y<picHeight) { if (color) { CPen pen(PS_SOLID ,radius*scalar,RGB(255,0,0)); CClientDC dc(this); CPen *pOldPen=dc.SelectObject(&pen); dc.MoveTo(tmpPre); dc.LineTo(point); dc.SelectObject(pOldPen); pushLine(color,point); //周围的点全都持久化-点前备份 //函数内翻译point 和tmpPre 周围点持久化 } else { CPen pen(PS_SOLID ,radius*scalar,RGB(0,0,255)); CClientDC dc(this); CPen *pOldPen=dc.SelectObject(&pen); dc.MoveTo(tmpPre); dc.LineTo(point); dc.SelectObject(pOldPen); pushLine(color,point); } tmpPre = point; } //=-------------------------------------------------------------------------------------- }
但是buffer中的点会有断点,计算断点间连线,并把线上点放入buffer,
为了计算直线,我使用的是y=kx+b,效果不好,会出现粗糙边缘。
改用OpenCV中cvLine的算法,很好的解决了问题。
void CiHairSegView:: pushLine(bool color, CPoint point){ //翻译tmpPre和point取之间的点(对应原图),加入序列 int x, y; //tempX,Y std::vector<CPoint> stack; //只一个不行啊 找出 满足 (x1-x2)y=(y1-y2)(x-x1)+y1(x1-x2) 的点加入 y_kx_b 集合做中间点 /* if (tmpPre.x==point.x) { int y1,y2; if (tmpPre.y>=point.y) {y1=tmpPre.y;y2=point.y;} else {y2=tmpPre.y;y1=point.y;} for (y=y2;y<=y1;y++){ stack.push_back(translate(CPoint(tmpPre.x,y))); } } else if (abs(tmpPre.x-point.x)==abs(tmpPre.y-point.y)){ int y1,y2,x1,x2; bool posNeg; if (tmpPre.y>=point.y) {y1=tmpPre.y;y2=point.y;x1=tmpPre.x;x2=point.x;} else {y2=tmpPre.y;y1=point.y;x2=tmpPre.x;x1=point.x;} if (x1>x2) posNeg=true; else posNeg=false; if (posNeg) for (y=y2;y<=y1;y++){ stack.push_back(translate(CPoint(x2++,y))); } else for (y=y2;y<=y1;y++){ stack.push_back(translate(CPoint(x2--,y))); } } else { int x1,x2,y1,y2; if (tmpPre.x>point.x) {x1=point.x; x2=tmpPre.x;} else {x1=tmpPre.x;x2=point.x;} if (tmpPre.y>point.y) {y1=point.y; y2=tmpPre.y;} else {y1=tmpPre.y;y2=point.y;} for (x=x1;x<=x2;x++) for (y=y1;y<=y2;y++) if (abs(y-tmpPre.y - (x-tmpPre.x)*(tmpPre.y-point.y)/(tmpPre.x-point.x))<2) { stack.push_back(translate(CPoint(x,y))); } } */ //用OpenCV画线函数选点 int pt1x,pt2x,pt1y,pt2y; pt1x=point.x; pt1y=point.y; pt2x=tmpPre.x; pt2y=tmpPre.y; if (pt1x>pt2x){ int tempx=pt1x; int tempy=pt1y; pt1x=pt2x; pt1y=pt2y; pt2x=tempx; pt2y=tempy; } int temp=pt1x; pt2x=pt2x-pt1x; pt1x=0; int count = -1; int dx, dy, s; int bt_pix, bt_pix0; unsigned step= abs(pt2x-pt1x)+1; bt_pix0 = 1; bt_pix = 1; dx = pt2x - pt1x; dy = pt2y - pt1y; s = dx < 0 ? -1 : 0; dx = (dx ^ s) - s; dy = (dy ^ s) - s; pt1x ^= (pt1x ^ pt2x) & s; pt1y ^= (pt1y ^ pt2y) & s; s = dy < 0 ? -1 : 0; dy = (dy ^ s) - s; step = (step ^ s) - s; step = pt2x-pt1x+1; int ptr = pt1y * step + pt1x * bt_pix0; s = dy > dx ? -1 : 0; dx ^= dy & s; dy ^= dx & s; dx ^= dy & s; bt_pix ^= step & s; step ^= bt_pix & s; bt_pix ^= step & s; int err = dx - (dy + dy); int plus_delta = dx + dx; int minus_delta = -(dy + dy); int plus_step = step; int minus_step = bt_pix; count = dx + 1; step =abs(pt2x-pt1x)+1; stack.push_back(translate(CPoint(ptr%step+temp,ptr/step))); for (int i=1;i<count;i++) { int _line_iterator_mask = err < 0 ? -1 : 0; err += minus_delta + (plus_delta & _line_iterator_mask); if (pt1y<=pt2y) ptr += minus_step + (plus_step & _line_iterator_mask); else { if (abs(pt1y-pt2y)>=step)ptr -= minus_step - (plus_step & _line_iterator_mask); else ptr += minus_step - (plus_step & _line_iterator_mask); } stack.push_back(translate(CPoint(ptr%step+temp,ptr/step))); } // 设置周围的点(笔粗) int r; float r1; if (scalar<=1.10&&scalar>=0.80) { r=(radius)/2; r=(int)(r+0.5)*scalar; r1=(radius)/2.0000; r1=r1*scalar; } else if (scalar>1.10){ r=(radius-3)/2; r=(int)(r+0.5)*scalar; r1=(radius-3)/2.0000; r1=r1*scalar; } else { r=(radius+2)/2; r=(int)(r+0.5)*scalar; r1=(radius+2)/2.0000; r1=r1*scalar; } std::vector <CPoint>::iterator it; for( it = stack.begin() ; it != stack.end() ; it++) { int maxX=it->x+r>picWidth?picWidth:it->x+r; int maxY=it->y+r>picHeight?picHeight:it->y+r; int minX=it->x-r<0?0:it->x-r; int minY=it->y-r<0?0:it->y-r; for (x=minX; x<=maxX; x++){ for ( y=minY; y<=maxY; y++){ short int tmpX=x-it->x; short int tmpY=y-it->y; if ( (float)(tmpX*tmpX+tmpY*tmpY)<r1*r1) { if (color) TIMAGE_PIX(GetDocument()->m_map, x, y) = TrimapForeground; else TIMAGE_PIX(GetDocument()->m_map, x, y) = TrimapBackground; } } } } }
然后按照笔刷的粗细,对邻域内的笔刷对应的型号进行图片持久化操作。然后清空buffer,我们完成了画一笔的操作。