回 帖 发 新 帖 刷新版面

主题:[转帖]算法讨论之:图像处理

要过年了,大伙可能会去玩玩,拍一些照片,从理论上来说,照片修改是不能作为法庭证据的,可我们毕竟不是为了打官司,我们为了玩,就顾不上什么了?
  有空用自己做的图片处理程序来改改自己做的一些图片,那也是一件美事。

  牛刀今天教大家做程序,暂时不用 VC 了,用VB与大伙儿试试,看看牛刀的VB编程功底还在也不在,呵呵。

  主要是VB使用起来的确方便,大家打开VB工程(注:如果没有去下载一个精简版的,很小很可爱,玩玩还真是挺带劲的,说实话,牛刀如果做一个很简单的小程序,如批量修改文本啊这些东东,还是很喜欢使用VB的,毕竟VB中没有字符的困扰啊,请大伙注意了,VB中,对中文字符与对西文字符的处理是一样的,有空再与大伙详细地说,呵呵)。

  打开VB,看图一,为窗体上加上两个图片框,与一个按钮,修改图片框的名称为“P”与“Pp”,呵呵,牛刀喜欢这样做,做起程序简单啊,当然这是跟大伙儿讲理论,或者自己做着玩,要做一个正规的软件,那可就要注意命名原则了,呵呵:在“P”图片框上贴上一幅图,什么图都可以,当然最好与背景反色大些的那更好,呵呵。(注意喽,可以直接将图片复制到剪切板,然后再粘过来就一切OK了。方便啊)
  现在就要开工喽:

  下面我们双击按钮,在屏幕上出现了一个子程序(注意:在VB中我们称之为子程序,而不是函数,呵呵,或者称之为方法)。

  我们在其中输入一些代码: Private Sub Command1_Click()

    P.Scale (0, 0)-(400, 400) '为图片设置长度与宽度以及坐标,一句话,呵呵,方便啊,以下同理

    Pp.Scale (0, 0)-(400, 400) '大家注意喽,VB不用担心大小写,大家想怎么打就怎么打,我们只要一换行,系统直接为我们改。

    For i = 0 To 400    'VB中的数据不需要提前定义,可以直接使用,但注意不要打错喽,错了系统查不出来的。

        For j = 0 To 400

            Pp.PSet (i, j), P.Point(i, j) '一句话,实现了什么功能呢?

        Next

    Next

End Sub
复制代码  这就是最简单的图片处理了,怎么处理了呢?将第一幅图片复制到第二幅图片上来了。(注:大家上机去试着玩玩吧,牛刀不忙着贴图上来了,没意思,呵呵。

  那么我们就先展开我们的图片处理的理论吧,图片我们分三原色,在美术中是:红、黄、蓝。可由于那是反射光造成的,而对于我们可以产生光的显示器来说,三原色却是红、绿、蓝,其实说实话,颜色都是我们眼睛产生的错觉,因为我们的眼睛也只有三种对颜色敏感的细胞,但为什么显示器上用红绿蓝,那具体也不清楚,就是那么定义的呗,有些东东,如果要追根,那就不是学电脑的人的事了,我们知道有这么回事就行了。那么我们下面就试着将这三种颜色给分离出来。 Function GetRVal(Rgb As Long) As Long

    Dim R As Integer

    R = Rgb Mod 256

    GetRVal = R

End Function

Function GetGVal(Rgb As Long) As Long

    Dim G As Integer

    G = (Rgb \ 256) Mod 256

    GetGVal = G

End Function

Function GetBVal(Rgb As Long) As Long

    Dim B As Integer

    B = (Rgb \ 256 \ 256) Mod 256

    GetBVal = B

End Function

Private Sub Command1_Click()

    P.Scale (-1, -1)-(401, 401) '为图片设置长度与宽度以及坐标,一句话,呵呵,方便啊,以下同理

    Pp.Scale (-1, -1)-(401, 401) '大家注意喽,VB不用担心大小写,大家想怎么打就怎么打,我们只要一换行,系统直接为我们改。

    For I = 0 To 400    'VB中的数据不需要提前定义,可以直接使用,但注意不要打错喽,错了系统查不出来的。

        For J = 0 To 400

            Pp.PSet (I, J), Rgb(GetRVal(P.Point(I, J)), GetGVal(P.Point(I, J)), GetBVal(P.Point(I, J))) '一句话,实现了什么功能呢?

        Next

    Next

End Sub
复制代码  上面的程序与前面的功能一样,因为我们的 RGB 值是一个长整型,并且之间都有256倍的关系,所以我们用了几个 GetRVal 等,将颜色分离开来,为什么要这样呢?因为下面有用,例如我们如果要为照片加一个红色的滤镜怎么加呢?我们只将红色部分过滤出来,其他部分用最小值就一切OK了:(最小值当然就是零,呵呵,没有负数啊) Private Sub Command1_Click()

    P.Scale (-1, -1)-(401, 401)

    Pp.Scale (-1, -1)-(401, 401)

    For i = 0 To 400

        For j = 0 To 400

            R = GetRVal(P.Point(i, j))

            Pp.PSet (i, j), Rgb(R, 0, 0)

        Next

    Next

End Sub
复制代码  VB中做程序简单吧?事实就是如此,当然如果我们要做绿色滤镜与蓝色滤镜也是小菜一碟喽:
G=GetGVal(P,Point(i,j))
Pp.Pset(i,j),Rgb(0,G,0)

B=GetBVal(P.Point(i,j))
Pp.Pset(i,j),Rgb(0,0,B)

  大家可以自己去试试,挺好玩,当然你也可以将滤镜中的其他值(0值)改了,做成其他的滤镜,例如,我们做个黄色滤镜吧: Private Sub Command1_Click()

    P.Scale (-1, -1)-(401, 401)

    Pp.Scale (-1, -1)-(401, 401)

    For i = 0 To 400

        For j = 0 To 400

            R = GetRVal(P.Point(i, j))

            G = GetGVal(P.Point(i, j))

            Pp.PSet (i, j), Rgb(R, G, 0)

        Next

    Next

End Sub
复制代码  做出来的挺漂亮,花瓣变成黄色的了,对了,如果我们将其中的三个数据取平均值,那就是标准的黑白照片了,绝对是最传统的黑白照:     P.Scale (-1, -1)-(401, 401)

    Pp.Scale (-1, -1)-(401, 401)

    For i = 0 To 400

        For j = 0 To 400

            R = GetRVal(P.Point(i, j))

            G = GetGVal(P.Point(i, j))

            B = GetBVal(P.Point(i, j))

            K = ((R + G + B) / 3) Mod 256 '注意不让其越界

            Pp.PSet (i, j), Rgb(K, K, K) '三个一样就是黑白世界,呵呵

        Next

    Next
复制代码  注意哟,绝对的黑白照片的效果哟,当然要做底片效果更简单:只要每一个都用 255一减就一切 OK 了:
  Pp.PSet (i, j), Rgb(255 - R, 255 - G, 255 - B)
  千万注意不是用 256减,是用255,很简单如果我们想要得到一些漏光的效果,我们设定一个值,判断一下,然后用相应的数字一减,我们漏的那一部分光就会在我们的软件中显示出来,看程序: Private Sub Command1_Click()

    P.Scale (-1, -1)-(401, 401)

    Pp.Scale (-1, -1)-(401, 401)

    For i = 0 To 400

        For j = 0 To 400

            R = GetRVal(P.Point(i, j))

            G = GetGVal(P.Point(i, j))

            B = GetBVal(P.Point(i, j))

            If R < 75 Then R = 255 - R '设置漏光阀域,当然也可以向亮处漏,用大于号就一切OK了

            Pp.PSet (i, j), Rgb(R, G, B)

        Next

    Next

End Sub
复制代码  当然你可以设置一个更小的值,我们程序做出来,我们这儿漏红光漏得一塌糊涂,大家可以做一些自己的效果,同理也可以做出一些曝光效果,一样的,关键是要看我们的“算法”。
  当然我们也可以做一些比较“恶心”的举动,例如将颜色值给“反”过来,这在传统的照片上,甚至多数的照片处理软件中,可能都是没有的,会做程序就是好啊,呵呵,看程序: Private Sub Command1_Click()

    P.Scale (-1, -1)-(401, 401)

    Pp.Scale (-1, -1)-(401, 401)

    For i = 0 To 400

        For j = 0 To 400

            R = GetRVal(P.Point(i, j))

            G = GetGVal(P.Point(i, j))

            B = GetBVal(P.Point(i, j))

            Pp.PSet (i, j), Rgb(B, G, R)

        Next

    Next

End Sub
复制代码  颜色反过来看还可以,能够接受,这就我们所谓的照片处理了,其实想想很简单,我们只要拿到三个颜色值,我们想怎么处理就怎么处理,这就是我们的“照片处理”,只要我们有一个构思,就可以立马去看看其效果。
  值得一提的是,我们可以用 if 语句去判断一个值,使得我们的程序可以随着我们的心思自由地变换,甚至很容易地将图像与背景分开,我们只需要设定一个阀域,然后将在某个阀域内的所有像素都统一就可以很容易地将我们的照片与我们背景分离开来,说实话,比哪一款图像处理软件都要来得方便,当然如果背景与人物的反差不是很大,那分离背景的工作就会显得很难。
  当然,我们的photoshop等软件用的技术也是这样,大同小异。

  以上都是对一个像素进行处理,下面我们对两个像素进行处理,作为“抛砖引玉”吧,大家都可以做出自己的软件出来。 Private Sub Command1_Click()

    P.Scale (-1, -1)-(401, 401)

    Pp.Scale (-1, -1)-(401, 401)

    For i = 1 To 400

        For j = 1 To 400

            R1 = GetRVal(P.Point(i, j))

            G1 = GetGVal(P.Point(i, j))

            B1 = GetBVal(P.Point(i, j))

            R2 = GetRVal(P.Point(i - 1, j - 1))

            G2 = GetGVal(P.Point(i - 1, j - 1))

            B2 = GetBVal(P.Point(i - 1, j - 1))

            R = (125 + Abs(R1 - R2)) Mod 255

            G = (125 + Abs(G1 - G2)) Mod 255

            B = (125 + Abs(B1 - B2)) Mod 255

            Pp.PSet (i, j), Rgb(R, G, B)

        Next

    Next

End Sub
复制代码  上面的程序可以实现一个板画效果的图片处理,当然,我们可以扩大点之间的距离,或者将三种颜色都取平均,那么就可以实现更加舒服的板画效果,甚至可以与真正的板画相媲美。
  当然我们就很容易想到喽,我们可以将周围的9个像素或25个像素取平均值,就可以实现图像的模糊,我们只要将周围的25个或36个像素都用平均值填充,就可以实现图片的马赛克效果,当然我们还可以根据周围的像素值去判断,从而产生边缘突显效果。

  而对于周围的若干像素进行处理的这种方案,可以很容易地做成一个通用的程序,甚至可以与软件独立开来,对于那种东东,我们称之为“滤镜”。当然,我们还可以更大范围地对像素之间找出相应的联系,就可以很容易地开发出专用效果的滤镜,如“素描效果”、“蜡笔画效果”、“水墨画效果”、“水粉画效果”,当然,能够实现这些效果的方法做成了程序,我们就称之为“算法”,或者是“图像算法”。

  还有一种算法,我们称之为“图像的扭曲”,这种就需要各种事实的物理学方面的知识了,例如,我们怎么在一幅画上做上一个水滴效果,怎么将一幅图片的某一部分做成球面效果,怎么将我们的图片贴到一个立体的图片上,或者让某个图片在模拟的三维空间中去放大,缩小,剪切,变换。

  甚至我们可以用算法将某个图片做成按钮的效果,镜框的效果,透视的效果,甚至加上一些光照效果,可以使得我们的图片在电脑上显得栩栩如生。

  好了,我们不说这些理论了,我们做一个效果来结束我们这一讲吧,我们看图三,我们将某一个像素在球面上做投影: Private Sub Command1_Click()

    pi = 3.141592654

    R = 3

    sr = 0.5

    P.Scale (-4, -4)-(4, 4)

    Pp.Scale (-4, -4)-(4, 4)

    For cti = -3.95 To 3.95 Step 0.01

        For ctj = -3.95 To 3.95 Step 0.01

            ctl = Sqr(cti * cti + ctj * ctj)

            If ctl < pi Then

                h = ctl * (R * (R / (ctl * ctl + R * R))) / sr

                hi = cti * h / ctl

                hj = ctj * h / ctl

                Pp.PSet (cti, ctj), P.Point(hi, hj)

            Else

                Pp.PSet (cti, ctj), P.Point(cti, ctj)

            End If

        Next

    Next

End Sub
复制代码  上面的程序做出来的效果不是太好,大家可以自主地改变 sr 与 r 值去调整调整,以便得到更好的效果。
  就是这样的效果,我们可以做成一个滤镜,当然不是指上面的滤镜了,去用鼠标去直接在照片上改,可以很容易地设置两个值就可以调节人物的高矮胖瘦,甚至做出一些恶心的作品来,呵呵。

  当然还可以将像素贴在球面上,然后根据我们眼睛位置去算出一些球面的效果,如果作图片处理的话比上面的效果还要好,从物理学的角度去做软件,我们以后作一个专题的一讲,合理使用甚至可以达到实物模拟的效果,很多的3D技术就是用的这些效果,如果再加上一些贴图,效果会很好的,甚至塑料效果,金属效果都可以做得出来。

  好了,这次我们就讨论到这儿吧,如果大家有兴趣,使用VC可以将一些算法做成成品的软件,以便达到我们自己的目的,去制作自己的图片处理软件。

回复列表 (共4个回复)

沙发

图象处理不了解,但比较有兴趣;VB就不会了,小弟只用过C++,会写一些小程序。
现在没什么时间,以后有机会一定好好学学图象处理。

板凳

http://blog.163.com/maijianquan_123/edit/ 
进入本人博客,
叫你身边的老虎机变成提款机器(私人资料,非诚勿扰)

3 楼


vb兄弟不懂,不过感觉做得挺好的嘛

4 楼

学习

我来回复

您尚未登录,请登录后再回复。点此登录或注册