c/c++ 检测图像中圆弧半径

神仙约架 2012-11-04 09:59:48

如图所示
怎么大致得到图中同心圆的3个半径?
难为了40天了, 请各位给个思路吧~谢谢
...全文
701 16 打赏 收藏 转发到动态 举报
写回复
用AI写文章
16 条回复
切换为时间正序
请发表友善的回复…
发表回复
dearpeer 2014-06-22
  • 打赏
  • 举报
回复
楼主 可以给这个程序代码发给我看看不 我也是类似的问题 愁死我了 dearpeer@126.com 如果没有了源代码可以给个详细点的思路不? 谢谢
神仙约架 2012-11-23
  • 打赏
  • 举报
回复
引用 14 楼 liangjing815 的回复:
,不能很精确,但是可以大概计算出位置,给个思路:连通域搜寻+数学运算
你好,已经很强大了,我现在用的方法是直接细化图像,然后取外接方框的上下值差取得直径,能把这个程序发给我看看嘛?我c学的不精,能读懂程序的水平,我邮箱sqqwm@163.com
liangjing815 2012-11-21
  • 打赏
  • 举报
回复
,不能很精确,但是可以大概计算出位置,给个思路:连通域搜寻+数学运算
xumaojun 2012-11-09
  • 打赏
  • 举报
回复
用数学知识,建立坐标系,弧上取两点做切线然后找垂线,两垂线相交的就是圆心,找到圆心就知道半径啦。
流氓码农 2012-11-09
  • 打赏
  • 举报
回复
我觉得边缘分割(联通域分析也可以)关键是提取边界点,然后拟合圆方程就可以了吧,而且你这个可以拟合出六个圆六个圆心,做个平均速度还是很快的吧,然后圆心有了,半径自然有了。
钟球盛 2012-11-08
  • 打赏
  • 举报
回复
1、选用大于最大圆环模版圆环去在整张图像中滑动匹配, 2、如果不存在,就缩小圆环的半径,进行步骤1,这个步长也可以变,直到找到最大圆环,圆心和半径马上知道; 3、剩下来的两个圆就有很多种方法了,发挥你的创造力量!
libralibra 2012-11-07
  • 打赏
  • 举报
回复
引用 5 楼 sqqwm 的回复:
引用 3 楼 libralibra 的回复:二值化,hough检测圆 我实在实时视频处理过程中处理图像,霍夫变换速度好像跟不上
要实时,你就得对精度需求降低一点 给你个思路,由于这些弧线是断开的,你可以得到两端点的坐标 然后垂直从中间切一下,得到第三点坐标,3个点可以找到半径了,基本都是数学运算,应该速度快点,不过你要测试一下才知道成不成
ndy_w 2012-11-05
  • 打赏
  • 举报
回复
你可以先纵横投影确定包含白色的最小矩形,再hough变换。 快一点的办法,可以从上下两端搜索边界,用边界点拟合圆。有了圆心就好弄了。
神仙约架 2012-11-05
  • 打赏
  • 举报
回复
引用 3 楼 libralibra 的回复:
二值化,hough检测圆
我实在实时视频处理过程中处理图像,霍夫变换速度好像跟不上
神仙约架 2012-11-05
  • 打赏
  • 举报
回复
引用 2 楼 franzhong 的回复:
我狂想一下啊 在一条弧上取一个点A,找临弧上点B 只要这个AB距离是最短的,这个AB直线必过圆心 找两条这个的线,交点,就是圆心 有了圆心,与弧上随便哪个点的距离都是半径
谢谢,我描述有点错误,如果这3条不是同心圆呢? 还有,这几条圆弧是有宽度的,还需要找中脊线才行
NexTor 2012-11-05
  • 打赏
  • 举报
回复
我认为,用圆弧上的三点来解方程来得到圆心应该可行吧。 先检测出外弧,然后在外弧上确定三个点,然后得到两个中垂线的方程,用编程解方程能得出圆心点坐标吧,然后就可以通过两点间距离算出半径了。 检测圆弧的话可以从一个方向向内找,第一个遇到的点肯定是在外弧上的点吧,然后可以定位到里面的各个弧的点。 解方程的话应该计算量比较小一些吧,会快一些吧
libralibra 2012-11-05
  • 打赏
  • 举报
回复
二值化,hough检测圆
东西北 2012-11-05
  • 打赏
  • 举报
回复
取弧形连通区域边界点,拟合圆。下面是拟合圆的函数 void TSL_Com_LeastSquaresFitting(CList<CPoint, CPoint &> & ltPt,MyCirStu &cir) { if (ltPt.GetCount()<3) { return; } int i=0; double X1=0; double Y1=0; double X2=0; double Y2=0; double X3=0; double Y3=0; double X1Y1=0; double X1Y2=0; double X2Y1=0; POSITION pos=ltPt.GetHeadPosition(); CPoint temppt; for (i=0;i<ltPt.GetCount();i++) { temppt = ltPt.GetNext(pos); X1 = X1 + temppt.x; Y1 = Y1 + temppt.y; X2 = X2 + temppt.x*temppt.x; Y2 = Y2 + temppt.y*temppt.y; X3 = X3 + temppt.x*temppt.x*temppt.x; Y3 = Y3 + temppt.y*temppt.y*temppt.y; X1Y1 = X1Y1 + temppt.x*temppt.y; X1Y2 = X1Y2 + temppt.x*temppt.y*temppt.y; X2Y1 = X2Y1 + temppt.x*temppt.x*temppt.y; } double C,D,E,G,H,N; double a,b,c; N = ltPt.GetCount(); C = N*X2 - X1*X1; D = N*X1Y1 - X1*Y1; E = N*X3 + N*X1Y2 - (X2+Y2)*X1; G = N*Y2 - Y1*Y1; H = N*X2Y1 + N*Y3 - (X2+Y2)*Y1; a = (H*D-E*G)/(C*G-D*D); b = (H*C-E*D)/(D*D-G*C); c = -(a*X1 + b*Y1 + X2 + Y2)/N; double A,B,R; A = a/(-2); B = b/(-2); R = sqrt(a*a+b*b-4*c)/2; cir.CirCenter.x = int(A+0.5); cir.CirCenter.y = int(B+0.5); cir.iRadius = int(R+0.5); return; }
franzhong 2012-11-04
  • 打赏
  • 举报
回复
我狂想一下啊 在一条弧上取一个点A,找临弧上点B 只要这个AB距离是最短的,这个AB直线必过圆心 找两条这个的线,交点,就是圆心 有了圆心,与弧上随便哪个点的距离都是半径
MicroDraw图形控件最新版本 最新版本详情咨询:VX:zhangty426 MicroDraw SDK For Windows,支持windows9x/ME/XP/7/8 发行方式:单机版、开发版本、网络版、B/S版本; MicroDraw图形控件是国内专业图形组件(间件),兼容多种CAD/GIS文件格式和操作方式; MDF,DWG,DXF,DWF,DXB,DGN,QCD,IGS,MDF,PLT,HPGL,MIF。并提供500多种方法和属性供开发者调用。可以用于开发行业(CAD/GIS/GPS)软件(如:建筑CAD,机械CAD,服装CAD等),数据加工软件(CAD/CNC)(如:线切割软件,激光打标软件),管理软件(MIS/PDM/ERP/MRP2/CAPP,图档管理),监控系统(煤矿,电力,电讯,煤气,消防等行业) 运行环境: 操作系统:Windows 9x/me/nt/2k/xp /win7/8 WinServer2003/2008 编程语言:Viusal Basic/Viusal C++/Delphi/ASP/IE/Powerbuild/Viusal Foxpro/C++ Builder/.NET(vb.net c# vc.net)/易语言 文件管理功能: 1. 支持的文件格式包括:BMP、GIF、ICO、TGA、PCX、WBMP、WMF、JPEG、PNG、MNG、TIFF、JBIG、PNM,PPM,PGM、RAS,DXF ,DWF(4.0-6.0)、DWG(2.5-2014) 、IGS, PDF、MIF,PLT,PRN,HPGL/HPGL2、DGN, SHP,CGM; 2. 打开图形图像文件;支持从URL/ftp网上打开,可以将文件保存到ftp上; 3. 打印文件:全部打印和选择打印,打印预览, 打印到文件; 4. 保存和读取自定义格式文件; 5. 将矢量图以指定的尺寸保存为光珊图或者复制到系统粘贴板上; 6. 插入OLE对象,OFFICE文档。 7. 支持模型及其布局文件的浏览。 8. 在不打开文件的情况下,导入文件的某个图层; 9. 对比文件; 10. 支持FTP服务器文件的导入;. 11. 支付PDF文件的浏览和打印; 12. 设置缺省文件格式模式的显示; 打印功能: 1. 直接对当前文件进行打印; 2. 单单的打印框选的元素; 3. 预览打印; 4. 打印出图时附加打印公司标示及其文本信息; 5. 设置水印并在出图时打印水印; 显示功能: 1. 显示平移,自由缩放,框选放大,最佳显示; 2. 回溯显示; 3. 支持显示透明命令操作; 4. 支持三维文件格式显示; 5. 鸟瞰,鹰眼,放大镜功能; 6. 显示网格,显示十字光标; 7. 显示元素外框控制点,同时通过元素控制点对元素进行控制放大、缩小、旋转; 8. 显示或者隐藏元素,图层元素; 9. 设置背景图片 10. 自定义图库文件。 11. 右键菜单功能; 12. 增加了显示水印功能 13. 显示或者隐藏工具条的指定按钮; 支持事件 1. 支持鼠标移动、点击、双击及滚轮操作事件; 2. 支持键盘的按下、抬起事件; 3. 支持显示绘制事件,用户可以自定义元素显示样式; 4. 支持多种缺省工具操作事件,缺省工具对元素进行操作都会触发相应事件; 5. 保存、打开、打印文件触发相应事件; 6. 文件上传和下载触发相应事件; 7. 选择操作后会触发相应事件; 元素支持功能: 1. 点;直线,折线,射线;圆,圆弧;椭圆,椭圆弧;样条线;函数曲线;填充区域,位图填充;多义线,文字,轨迹文字,剖面线; 2. 文字标注,尺寸标注(水平,竖直,对齐,角度,半径,直径尺寸等); 3. 块插入、图片插入、OLE对象; 4. 多边形; 5. 基本三维元素创建; 6. 图层、文字样式、尺寸样式、线型、剖面线填充样式等; 编辑构造功能: 1. 删除、复制、粘贴、镜像、移动、旋转、延伸、修剪、拖拽、缩放、圆形阵列、矩形阵列; 2. undo /redo 3. 组合、炸开;炸开文字; 其他可选模块: 1. 算法模块,计算图形的长度、面积、体积、交点等; 寻找最大封闭区域、最小 封闭区域、偏移元素;有限元分析算法;图形比较算法;区域求交算法等; 2.数控加工模块,提取几何元素加工数据;优化加工路径; 3.图库功能,自定义图库; 4.视频测绘模块,将cad图纸和视频内容进行叠加比对;
8-1 用QPainter绘图(Painting with QPainter) 2011-10-26 19:56:04| 分类: 默认分类 | 标签: |字号大小 订阅 8-1 用QPainter绘图(Painting with QPainter) 分类: C++ GUI Programming with Qt 4 2007-05-29 21:52 8228人阅读 评论(3) 收藏 举报 要在绘图设备(paint device,一般是一个控件)上开始绘制,我们只要创建一个QPainter,把绘图设备指针传给QPainter对象。例如: oid MyWidget::paintEvent(QPaintEvent *event) { QPainter painter(this); ... } 使用QPainter的draw…()函数我们可以绘制各种图形。图8.1给出了主要的一些。绘制的方式由QPainter的设置决定。设置的一部分是从绘图设备得到的,其他是初始化时的默认值。三个主要的设置为:画笔,刷子和字体。 画笔用来绘制直线和图形的边框。包含颜色,宽度,线型,角设置和连接设置。 刷子是填充几何图形的方式。包含颜色,方式设置,也可以是一个位图或者渐变色。 字体用来绘制文本。字体的属性很多,如字体名,字号等。 这些设置随时可以改变,可用QPen,QBrush,QFont对象调用setPen(),setBrush(),setFont()修改。 Figure 8.1. QPainter's most frequently used draw...() functions Figure 8.2. Cap and join styles < XMLNAMESPACE PREFIX ="O" /> < XMLNAMESPACE PREFIX ="V" /> Figure 8.3. Pen styles Figure 8.4. Predefined brush styles 现在来看看具体的例子。下面的代码是绘制图8.5(a)椭圆的代码: QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing, true); painter.setPen(QPen(Qt::black, 12, Qt::DashDotLine, Qt::RoundCap)); painter.setBrush(QBrush(Qt::green, Qt::SolidPattern)); painter.drawEllipse(80, 80, 400, 240); 调用函数setRenderHint(QPainter::Antialiasing,true),使绘制时边缘平滑,使用颜色浓度的变化,把图形的边缘转换为象素时引起的扭曲变形尽可能减少,在支持这一功能的平台或者绘图设备上得到一个平滑的边缘。 Figure 8.5. Geometric shape examples 下面的代码是图8.5(b)绘制扇形的代码: QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing, true); painter.setPen(QPen(Qt::black, 15, Qt::SolidLine, Qt::RoundCap, Qt::MiterJoin)); painter.setBrush(QBrush(Qt::blue, Qt::DiagCrossPattern)); painter.drawPie(80, 80, 400, 240, 60 * 16, 270 * 16); 函数drawPie()的最后两个参数值的单位为一度的十六分之一。 下面的代码是图8.5(c)绘制贝赛尔曲线的代码: QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing, true); QPainterPath path; path.moveTo(80, 320); path.cubicTo(200, 80, 320, 80, 480, 320); painter.setPen(QPen(Qt::black, 8)); painter.drawPath(path); 通过连接基本图形元素,直线,椭圆,多段线,圆弧,二次和三次贝塞尔曲线等,QPainterPath类能确定任何矢量图形。因此,绘图路径(Painter paths)是最基本的绘制元素,任何图形和图形的组合都可以同路径(path)表示。 一个路径能够确定一个轮廓,由这个轮廓确定的区域可以由刷子来填充。在图8.5(c)我们没有设置刷子,因此只绘制了轮廓。 以上的三个例子都是使用了默认的刷子(Qt::SolidePattern,Qt::DiagCrossPattern,Qt::NoBrush)。在现在的应用程序,单色填充已经很少使用,渐变色填充开始收到欢迎。渐变是依靠颜色的变化实现两种或者多种颜色之间平滑的过渡。渐变通常用来处理3D效果,如使用Plastique渐变方式来表现QPushButtons。 Qt支持三种类型的渐变:线形渐变,圆锥渐变和圆形渐变(linear, conical, and radial)。下一节的OvenTimer例子就是在一个控件使用了所有这三种渐变。 线形渐变由两个控制点和直线上的一系列颜色点组成。图8.6由下面的代码得到:在两个控制点之间,在三个不同的位置确定了三个不同的颜色值。位置有0到1的浮点数得到,0为第一个控制点,1为第二个控制点。不同位置点之间的颜色由差值计算得到。 LinearGradient gradient(50, 100, 300, 350); gradient.setColorAt(0.0, Qt::white); gradient.setColorAt(0.2, Qt::green); gradient.setColorAt(1.0, Qt::black); Figure 8.6. QPainter's gradient brushes 圆形渐变由颜色组,圆心(xc,yc),半径r和焦点(xf,yf)定义。圆心和半径定义一个圆,颜色从焦点开始扩散到周围,焦点可以是圆心也可以是圆内的任意一个点。 圆锥渐变由圆心(xc,yc)和一个角度a定义。颜色从圆心开始像表的秒针一样扩散。 我们已经提到了QPainter的画笔,刷子和字体设置。此外,QPainter还有其他一些设置影响图形和文字的绘制: 1. 背景刷子,当背景模式为Qt::OpaqueMode(缺省值为Qt::transparentMode)时,背景刷子用来填充几何图形,文字,和位图的背景(在绘图刷子的下面) 2. 刷子的起点:刷子的起始绘制点,通常为控件的左上角。 3. 剪辑区域,剪辑区域为绘图设备上可以绘制的区域,在剪辑区域意外进行的绘制是无效的。 4. 视口,窗口,世界坐标:这三个决定了QPainter的逻辑坐标映射到物理坐标的方式。通常,逻辑坐标和物理坐标是重合的。坐标系统在下一节介绍。 5. 组合方式:组合方式决定绘制设备上新绘制的象素和已经存在的象素的影响方式。缺省方式为覆盖式(source over),新象素画在已有元素的上面。只是有限一个绘图设备支持组合方式的设置,将在本章后面介绍 在任何时候,我们可以调用save()把QPainter当前的设置保存在一个内部栈里,然后调用restore()进行恢复。我们能够临时改变QPainter的一些设置,然后恢复先前的值 Qt的二位图形引擎是基于 QPainter 类的。它既可以绘制几何形状,也可以绘制像素映射、图像和文字。自定义窗口部件需要重新实现 QWidget::paintEvent() 。 void Widget:: paintEvent( QPaintEvent * /*paintEvent*/ ) { draw(); drawBezier(); } void Widget:: draw() { QPainter painter( this ); painter. setPen( QPen ( Qt :: black, 10 , Qt :: DashDotLine, Qt :: RoundCap)); painter. setBrush( QBrush ( Qt :: green, Qt :: SolidPattern)); painter. drawEllipse( 10 , 10 , 400 , 240 ); painter. drawRect( QRect ( 10 , 300 , 400 , 140 )); } 首先需要创建一个 QPainter ,将需要绘图的设备的指针传递给 QPainter 。 QPainter 有各种 draw…() 可以绘制不同的图形。画笔、画刷、字体是最重要的三种设置。 画笔用来画线和边缘, QPainter ::setPen() 可以对画笔进行设置,包括颜色、宽度、线型、拐点风格等。 画刷用来填充几何形状的图案, QPainter ::setBrush() 可以对画刷进行设置,包括颜色和纹理风格。 绘制文本时需要对字体进行设置, QPainter ::setFont() 对字体进行设置,包括字体族和磅值。 void Widget:: drawBezier() { QPainter painter( this ); painter. setRenderHint( QPainter :: Antialiasing, true ); QPainterPath path; path. moveTo( 10 , 320 ); path. cubicTo( 200 , 80 , 400 , 80 , 480 , 320 ); painter. setPen( QPen ( Qt :: black, 8 )); painter. setBrush( QBrush ( Qt :: green, Qt :: DiagCrossPattern)); painter. drawPath( path); } QPainterPath 可以通过连接基本的图形单元元素来确定任意的矢量形状,包括:直线、椭圆、多边形、弧形、贝赛尔曲线等。 首先使用 QPainter ::moveto() 来确定图形的起点,然后通过 cubicTo() 来确定绘制的线路。前 4 个参数确定了两个控制点,后两个参数是结束点的位置。 修改函数如下: void Widget:: drawBezier() { QPainter painter( this ); painter. setRenderHint( QPainter :: Antialiasing, true ); QPainterPath path; path. moveTo( 10 , 320 ); path. cubicTo( 200 , 80 , 400 , 80 , 480 , 320 ); painter. setPen( QPen ( Qt :: black, 2 )); painter. drawPath( path); painter. setPen( QPen ( Qt :: red, 4 )); painter. drawPoint( 10 , 320 ); painter. drawPoint( 200 , 80 ); painter. drawPoint( 400 , 80 ); painter. drawPoint( 480 , 320 ); } 画笔样式 为了尝试画笔的样式,这里故意使用了一个新的画笔: painter.setPen(QPen(Qt::black, 5, Qt::DashDotLine, Qt::RoundCap)); 我们对照着API去看,第一个参数是画笔颜色,这里设置为黑色;第二个参数是画笔的粗细,这里是5px;第三个是画笔样式,我们使用了 DashDotLine,正如同其名字所示,是一个短线和一个点相间的类型;第四个是RoundCap,也就是圆形笔帽。然后我们使用一个黄色的画刷填充,画了一个椭圆。 后面的一个和前面的十分相似,唯一的区别是多了一句 painter.setRenderHint(QPainter::Antialiasing, true); 不过这句也很清楚,就是设置Antialiasing属性为true.如果你学过图形学就会知道,这个长长的单词就是"反走样".经过这句设置,我们就打开了QPainter的反走样功能。还记得我们曾经说过,QPainter是一个状态机,因此,只要这里我们打开了它,之后所有的代码都会是反走样绘制的了。 看到这里你会发现,反走样的效果其实比不走样要好得多,那么,为什么不默认打开反走样呢?这是因为,反走样是一种比较复杂的算法,在一些对图像质量要求不高的应用,是不需要进行反走样的。为了提高效率,一般的图形绘制系统,如Java2D、OpenGL之类都是默认不进行反走样的。 还有一个疑问,既然反走样比不反走样的图像质量高很多,不进行反走样的绘制还有什么作用呢?前面说的是一个方面,也就是,在一些对图像质量要求不高的环境下,或者说性能受限的环境下,比如嵌入式和手机环境,是不必须要进行反走样的。另外还有一点,在一些必须精确操作像素的应用,也是不能进行反走样的。请看下面的图片: 上图是使用Photoshop的铅笔和画笔工具画的1像素的点在放大到3200%视图下截下来的。Photoshop里面的铅笔工具是不进行反走样,而画笔是要进行反走样的。在放大的情况下就会知道,有反走样的情况下是不能进行精确到1像素的操作的。因为反走样很难让你控制到1个像素。这不是 Photoshop画笔工具的缺陷,而是反走样算法的问题。如果你想了解为什么这样,请查阅计算机图形学里面关于反走样的原理部分。 反走样是图形学的重要概念,用以防止“锯齿”现象的出现。很多系统的绘图API里面都会内置了反走样的算法,不过默认一般都是关闭的,Qt也不例外。下面我们来看看代码。这段代码仅仅给出了paintEvent函数,相信你可以很轻松地替换掉前面章节的相关代码。 void PaintedWidget::paintEvent(QPaintEvent *event) { QPainter painter(this); painter.setPen(QPen(Qt::black, 5, Qt::DashDotLine, Qt::RoundCap)); painter.setBrush(Qt::yellow); painter.drawEllipse(50, 150, 200, 150); painter.setRenderHint(QPainter::Antialiasing, true); painter.setPen(QPen(Qt::black, 5, Qt::DashDotLine, Qt::RoundCap)); painter.setBrush(Qt::yellow); painter.drawEllipse(300, 150, 200, 150); } 声明:本文原创于yafeilinux的百度博客,http://hi.baidu.com/yafeilinux 转载请注明出处。 前面一节我们讲解了图片的显示,其很多都用到了坐标的变化,这一节我们简单讲一下Qt的坐标系统,其实也还是主要讲上一节的那几个函数。这里我们先讲解一下Qt的坐标系,然后讲解那几个函数,它们分别是: translate()函数,进行平移变换;scale()函数,进行比例变换;rotate()函数,进行旋转变换;shear()函数,进行扭曲变换。 最后介绍两个有用的函数save()和restore(),利用它们来保存和弹出坐标系的状态,从而实现快速利用几个变换来绘图。 一、坐标系简介。 Qt每一个窗口都有一个坐标系,默认的,窗口左上角为坐标原点,然后水平向右依次增大,水平向左依次减小,垂直向下依次增大,垂直向上依次减小。原点即为(0,0)点,然后以像素为单位增减。 例如: void Dialog::paintEvent(QPaintEvent *) { QPainter painter(this); painter.setBrush(Qt::red); painter.drawRect(0,0,100,100); painter.setBrush(Qt::yellow); painter.drawRect(-50,-50,100,100); } 我们先在原点(0,0)绘制了一个长宽都是100像素的红色矩形,又在(-50,-50)点绘制了一个同样大小的黄色矩形。可以看到,我们只能看到黄色矩形的一部分。效果如下图。 二、坐标系变换。 坐标系变换是利用变换矩阵来进行的,我们可以利用QTransform类来设置变换矩阵,因为一般我们不需要进行更改,所以这里不在涉及。下面我们只是对坐标系的平移,缩放,旋转,扭曲等应用进行介绍。 1.利用translate()函数进行平移变换。 void Dialog::paintEvent(QPaintEvent *) { QPainter painter(this); painter.setBrush(Qt::yellow); painter.drawRect(0,0,50,50); painter.translate(100,100); //将点(100,100)设为原点 painter.setBrush(Qt::red); painter.drawRect(0,0,50,50); painter.translate(-100,-100); painter.drawLine(0,0,20,20); } 效果如下。 这里将(100,100)点作为了原点,所以此时(100,100)就是(0,0)点,以前的(0,0)点就是 (-100,-100)点。要想使原来的(0,0)点重新成为原点,就是将(-100,-100)设为原点。 2.利用scale()函数进行比例变换,实现缩放效果。 void Dialog::paintEvent(QPaintEvent *) { QPainter painter(this); painter.setBrush(Qt::yellow); painter.drawRect(0,0,100,100); painter.scale(2,2); //放大两倍 painter.setBrush(Qt::red); painter.drawRect(50,50,50,50); } 效果如下。 可以看到,painter.scale(2,2),是将横纵坐标都扩大了两倍,现在的(50,50)点就相当于以前的 (100,100)点。 3.利用shear()函数就行扭曲变换。 void Dialog::paintEvent(QPaintEvent *) { QPainter painter(this); painter.setBrush(Qt::yellow); painter.drawRect(0,0,50,50); painter.shear(0,1); //纵向扭曲变形 painter.setBrush(Qt::red); painter.drawRect(50,0,50,50); } 效果如下。 这里,painter.shear(0,1),是对纵向进行扭曲,0表示不扭曲,当将第一个0更改时就会对横行进行扭曲,关于扭曲变换到底是什么效果,你观察一下是很容易发现的。 4.利用rotate()函数进行比例变换,实现缩放效果。 void Dialog::paintEvent(QPaintEvent *) { QPainter painter(this); painter.drawLine(0,0,100,0); painter.rotate(30); //以原点为心,顺时针旋转30度 painter.drawLine(0,0,100,0); painter.translate(100,100); painter.rotate(30); painter.drawLine(0,0,100,0); } 效果如下。 因为默认的rotate()函数是以原点为心进行顺时针旋转的,所以我们要想使其以其他点为心进行旋转,就要先进行原点的变换。这里的painter.translate(100,100)将(100,100)设置为新的原点,想让直线以其为心进行旋转,可是你已经发现效果并非如此。是什么原因呢?我们添加一条语句,如下: void Dialog::paintEvent(QPaintEvent *) { QPainter painter(this); painter.drawLine(0,0,100,0); painter.rotate(30); //以原点为心,顺时针旋转30度 painter.drawLine(0,0,100,0); painter.rotate(-30); painter.translate(100,100); painter.rotate(30); painter.drawLine(0,0,100,0); } 效果如下。 这时就是我们想要的效果了。我们加的一句代码为painter.rotate(-30),这是因为前面已经将坐标旋转了30度,我们需要将其再旋转回去,才能是以前正常的坐标系统。不光这个函数如此,这里介绍的这几个函数均如此,所以很容易出错。下面我们将利用两个函数来很好的解决这个问题。 三、坐标系状态的保护。 我们可以先利用save()函数来保存坐标系现在的状态,然后进行变换操作,操作完之后,再用restore()函数将以前的坐标系状态恢复,其实就是一个入栈和出栈的操作。 例如: void Dialog::paintEvent(QPaintEvent *) { QPainter painter(this); painter.save(); //保存坐标系状态 painter.translate(100,100); painter.drawLine(0,0,50,50); painter.restore(); //恢复以前的坐标系状态 painter.drawLine(0,0,50,50);

19,468

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 图形处理/算法
社区管理员
  • 图形处理/算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧