Python-OpenCV-PS油画滤镜效果

油画滤镜算法描述:

该算法有两个参数,一个是模板半径(radius),则模板尺寸是(radius * 2 + 1)*(radius * 2 + 1)大小(其实也可以偶数倍数无所谓的),也就是以当前像素为中心,向外扩展 radius 个像素的矩形区域作为一个搜索范围,我们暂时将它称为“模板”(实际上该算法并不是例如高斯模糊,自定滤镜那种标准模板法,仅仅是处理过程类似)。另一个参数是光滑度(smoothness),实际上他是灰度桶的个数。我们假设把像素的灰度/亮度( 0 ~ 255 )均匀的分成 n 个区间,则每个区间我们在此称它为一个桶(bucket),这样我们就有很多个桶,称之为桶列表(buckets)

(1)算法遍历图上的每个像素,针对当前位置 (x, y) 像素,将模板范围内的所有像素灰度化,即把图像变成灰度图像。

(2)把像素值进一步离散化,即根据像素的灰度落入的区间,把模板内的像素依次投入到相应的桶中

(3)从这些桶中找到一个落入像素个数最多的桶,并对该桶中的所有像素求出颜色平均值,作为位置 (x, y) 的结果值。文中使用桶阵列(8 个桶,即把0~255的灰度值离散化成 8 个区间段)。

import cv2
import numpy as np


def oilPainting(img, templateSize, bucketSize, step):#templateSize模板大小,bucketSize桶阵列,step模板滑动步长

    gray = cv2.cvtColor(img,cv2.COLOR_RGB2GRAY)
    gray = ((gray/256)*bucketSize).astype(int)                          #灰度图在桶中的所属分区
    h,w = img.shape[:2]
     
    oilImg = np.zeros(img.shape, np.uint8)                              #用来存放过滤图像
     
    for i in range(0,h,step):
        
        top = i-templateSize
        bottom = i+templateSize+1
        if top < 0:
            top = 0
        if bottom >= h:
            bottom = h-1
            
        for j in range(0,w,step):
            
            left = j-templateSize
            right = j+templateSize+1
            if left < 0:
                left = 0
            if right >= w:
                right = w-1
                
            # 灰度等级统计
            buckets = np.zeros(bucketSize,np.uint8)                     #桶阵列,统计在各个桶中的灰度个数
            bucketsMean = [0,0,0]                                       #对像素最多的桶,求其桶中所有像素的三通道颜色均值
            #对模板进行遍历
            for c in range(top,bottom):
                for r in range(left,right):
                    buckets[gray[c,r]] += 1                         #模板内的像素依次投入到相应的桶中,有点像灰度直方图
    
            maxBucket = np.max(buckets)                                 #找出像素最多的桶以及它的索引
            maxBucketIndex = np.argmax(buckets)
            
            for c in range(top,bottom):
                for r in range(left,right):
                    if gray[c,r] == maxBucketIndex:
                        bucketsMean += img[c,r]
            bucketsMean = (bucketsMean/maxBucket).astype(int)           #三通道颜色均值
            
            # 油画图
            for m in range(step):
                for n in range(step):
                    oilImg[m+i,n+j] = (bucketsMean[0],bucketsMean[1],bucketsMean[2])
    return  oilImg
    

img = cv2.imread(r'C:\Users\x\Desktop\92.jpg', cv2.IMREAD_ANYCOLOR)
oil = oilPainting(img,4,8,2)
cv2.imshow('youhua',oil)
cv2.imwrite(r'C:\Users\x\Desktop\97.jpg',oil)
cv2.waitKey(0)
cv2.destroyAllWindows()

这里templateSize模板大小就是矩形模板的宽,步长step可选择1,2,3等,1图片最为细致但是速度过慢,2速度快效果也不错,3速度最快但是图片成斑状。

结果:


你可以通过图像平滑来处理图片。

然后用一张油画纹理图片,通过图层混和算法来处理图片。

灵感来自这个博主:Matrix_11风吹夏天

PS图层混合算法之一(不透明度,正片叠底,颜色加深,颜色减淡)

下列公式中,A代表了上面图层像素的色彩值(A=像素值/255),B代表下面图层像素的色彩值(B=像素值/255),C代表了混合像素的色彩值(真实的结果像素值应该为255*C)。该公式也应用于层蒙板。    

不透明度模式:

C=d*A+(1-d)*B

相对于不透明度而言,其反义就是透明度。这两个术语之间的关系就类似于正负之间的关系:100%的不透明度就是0%的透明度。该混合模式相对来说比较简单,在该混合模式下,如果两个图层的叠放顺序不一样,其结果也是不一样的(当然50%透明除外)。该公式中,A代表了上面图层像素的色彩值(A=像素值/255),d表示该层的透明度,B代表下面图层像素的色彩值(B=像素值/255),C代表了混合像素的色彩值(真实的结果像素值应该为255*C)。该公式也应用于层蒙板,在这种情况下,d代表了蒙板图层中给定位置像素的亮度,下同,不再叙述。

正片叠底模式:

C=A*B

将两个颜色的像素值相乘,然后除以255得到的结果就是最终色的像素值。通常执行正片叠底模式后的颜色比原来两种颜色都深。任何颜色和黑色正片叠底得到的任然是黑色,任何颜色和白色执行正片叠底则保持原来的颜色不变,而与其他颜色执行此模式会产生暗室中以此种颜色照明的效果。像素点的像素值是0-255,黑色值是0,白色是255.

该效果将两层像素的标准色彩值(基于0..1之间)相乘后输出,其效果可以形容成:两个幻灯片叠加在一起然后放映,透射光需要分别通过这两个幻灯片,从而被削弱了两次。


颜色加深模式:

C=1-(1-B)/A

查看每个通道的颜色信息,通过增加“对比度”使底色的颜色变暗来反映绘图色,和白色混合没变化。

该模式和上一个模式刚好相反。如果上层越暗,则下层获取的光越少,如果上层为全黑色,则下层越黑,如果上层为全白色,则根本不会影响下层。结果最亮的地方不会高于下层的像素值。


颜色减淡模式:

C=B/(1-A)

查看每个通道的颜色信息,通过降低“对比度”使底色的颜色变亮来反映绘图色,和黑色混合没变化。

该模式下,上层的亮度决定了下层的暴露程度。如果上层越亮,下层获取的光越多,也就是越亮。如果上层是纯黑色,也就是没有亮度,则根本不会影响下层。如果上层是纯白色,则下层除了像素为255的地方暴露外,其他地方全部为白色(也就是255,不暴露)。结果最黑的地方不会低于下层的像素值。
 

import cv2

img = cv2.imread(r'C:\Users\x\Desktop\97.jpg',cv2.IMREAD_ANYCOLOR)
img1 = cv2.imread(r'C:\Users\x\Desktop\57.jpg',cv2.IMREAD_ANYCOLOR)
img2 = cv2.resize(img1, (658,986), interpolation=cv2.INTER_CUBIC)
d = 0.84
img3 = d*(img/255)+(1-d)*(img2/255)
img4 = img3*255
#cv2.imshow('youhua',img3)
cv2.imwrite(r'C:\Users\x\Desktop\101.jpg',img4)
cv2.waitKey(0)
cv2.destroyAllWindows()

结果:

待续。。。。。

猜你喜欢

转载自blog.csdn.net/qq_40755643/article/details/84787204