社区
其它技术问题
帖子详情
求Qt高质量反走样算法思路
马丁陈
2018-01-12 02:53:22
小弟最近在写一些程序代码,其中涉及一个圆的边缘反走样问题,其中使用Qt自带的反走样效果绘制(QPainter::setRenderHint)),反走样的顶端边缘特性如下图所示:
而小弟自己写的代码使用OpenGL,然后用高斯滤波(核5*5)的结果如下图所示:
从两张图的比较来看,边缘过渡效果不像Qt自带算法的过渡平滑、方向性强,请问各位大神,qt的这种反走样的实现是具体采用哪一种反走样算法?小弟曾经尝试看qt源码,但是因为能力有限实在是看不懂painter部分的实现。求大神点拨!
...全文
838
11
打赏
收藏
求Qt高质量反走样算法思路
小弟最近在写一些程序代码,其中涉及一个圆的边缘反走样问题,其中使用Qt自带的反走样效果绘制(QPainter::setRenderHint)),反走样的顶端边缘特性如下图所示: 而小弟自己写的代码使用OpenGL,然后用高斯滤波(核5*5)的结果如下图所示: 从两张图的比较来看,边缘过渡效果不像Qt自带算法的过渡平滑、方向性强,请问各位大神,qt的这种反走样的实现是具体采用哪一种反走样算法?小弟曾经尝试看qt源码,但是因为能力有限实在是看不懂painter部分的实现。求大神点拨!
复制链接
扫一扫
分享
转发到动态
举报
写回复
配置赞助广告
用AI写文章
11 条
回复
切换为时间正序
请发表友善的回复…
发表回复
打赏红包
糖少主
2019-01-23
打赏
举报
回复
Qt的反走样算法很像是Wu反走样,我最近自己实现了这个,但是觉得也不太理想
。
赵4老师
2018-01-16
打赏
举报
回复
Qt是开源的,看Qt反走样相关源代码。
赵4老师
2018-01-15
打赏
举报
回复
Qt底层没调用GDI+ ?
日立奔腾浪潮微软松下联想
2018-01-15
打赏
举报
回复
反走样处理本来就是为了视觉效果,不损失信息要保留原始图像。
马丁陈
2018-01-15
打赏
举报
回复
1
引用 7 楼 zhao4zhong1 的回复:
Qt底层没调用GDI+ ?
赵老师好,说实话小弟不是太看得懂qt源码,但是从网上的资料来看,qpainter及其相关类的确是对GDI的封装,但是即使知道是对GDI的封装了,那么在反走样方面有什么具体思路吗……
马丁陈
2018-01-15
打赏
举报
回复
引用 5 楼 bycy0801 的回复:
自己顶一下,不然沉了……
其实我就是想获得类似Qt自带效果的这种反走样= =,因为小弟从事的3d打印行业,这种反走样的效果是打印效果最好的
马丁陈
2018-01-13
打赏
举报
回复
自己顶一下,不然沉了……
马丁陈
2018-01-12
打赏
举报
回复
但是就是仍然没有获得类似qt的效果。。。
马丁陈
2018-01-12
打赏
举报
回复
其实小弟也知道看上去的话两侧图左边好一些,但是其实小弟翻阅过资料,高斯滤波的结果只是看上去效果很好,其实已经损失了很多信息,参见
http://blog.csdn.net/shenziheng1/article/details/50838970
或者以下截图
小弟还真去尝试了双边滤波,先高斯再双边滤波,结果如下
qq_41623444
2018-01-12
打赏
举报
回复
确实左边的还好些
日立奔腾浪潮微软松下联想
2018-01-12
打赏
举报
回复
没有多大差别,左侧看起来比Qt的处理还好一些。
QT
绘图函数
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)点绘制了一个同样大小的黄色矩形。可以看到,我们只能看到黄色矩形的一部分。效果如下图。 二、坐标系变换。 坐标系变换是利用变换矩阵来进行的,我们可以利用
QT
ransform类来设置变换矩阵,因为一般我们不需要进行更改,所以这里不在涉及。下面我们只是对坐标系的平移,缩放,旋转,扭曲等应用进行介绍。 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);
QT
编程入门系列文章之二十六——
反走样
今天继续前面的内容。既然已经进入2D绘图部分,那么就先继续研究一下有关QPainter的东西吧!
反走样
是图形学 中的重要概念,用以防止“锯齿”现象的出现。很多系统的绘图API里面都会内置了
反走样
的
算法
,不过默认一般都是关闭的,
Qt
也不例外。下面我们来看看代码。这段代码仅仅给出了paintEvent函数,相信你可以很轻松地替换掉前面章节中的相关代码。 void PaintedWidget::paintEvent(QPaintEvent *event) { QPainter painter(this.
QT
高级编程
QT
界面美化QSS
QT
网络编程
QT
绘图
QT
多线程视频课程
QT
课程学习目标这套
QT
课程体系是为准备从事以下软件工程师岗位工作的学员群体精心研发的。
QT
软件工程师
QT
高级软件工程师
QT
课程技术模块
QT
核心技术概念
QT
图形窗口编程技术
QT
QSS界面美化实战技术
QT
实用框架编程技术
QT
课程学习路线
QT
核心基础概念体系编程实践
QT
Widgets图形窗口编程基础体系编程实践
QT
基础控件和高级复杂控件体系编程实践
QT
布局管理体系编程实践
QT
模型视图代理框架编程实践
QT
QSS式样表编程实践
QT
界面美化编程实践
QT
文件IO框架编程实践
QT
绘图框架编程实践
QT
图形视图框架编程实践
QT
网络框架编程实践
QT
多线程框架编程实践
QT
线程池框架编程实践
QT
并发库框架编程实践
QT
课程推荐章节
QT
控件美化界面美化是这套
QT
课程中的特色亮点,是
QT
软件工程师在工作实践中可以直接参考应用的,推荐认真学习。
QT
QSS基础控件界面美化
QT
QSS高级控件界面美化
QT
QSS其它控件界面美化
QT
QSS窗口组合界面美化
QT
QSS主窗口界面美化
Qt
学习之路 2(26):
反走样
我们在光栅图形显示器上绘制非水平、非垂直的直线或多边形边界时,或多或少会呈现锯齿状外观。这是因为直线和多边形的边界是连续的,而光栅则是由离散的点组成。在光栅显示设备上表现直线、多边形等,必须在离散位置采样。由于采样不充分重建后造成的信息失真,就叫走样;用于减少或消除这种效果的技术,就称为
反走样
。
反走样
是图形学中的重要概念,用以防止通常所说的“锯齿”现象的出现。很多系统的绘图 API
Qt
反走样
(抗锯齿)
转载自:http://blog.chinaunix.net/uid-24219701-id-4044333.html
反走样
是图形学中的重要概念,用以防止通常所说的“锯齿”现象的出现。很多系统的绘图 API 里面都内置了有关
反走样
的
算法
,不过由于性能问题,默认一般是关闭的,
Qt
也不例外。//QPainter::Antialiasing 告诉绘图引擎应该在可能的情况下进行边的反锯齿
其它技术问题
3,881
社区成员
9,054
社区内容
发帖
与我相关
我的任务
其它技术问题
C/C++ 其它技术问题
复制链接
扫一扫
分享
社区描述
C/C++ 其它技术问题
社区管理员
加入社区
获取链接或二维码
近7日
近30日
至今
加载中
查看更多榜单
社区公告
暂无公告
试试用AI创作助手写篇文章吧
+ 用AI写文章