星鸿阁

 找回密码
 立即注册
搜索
热搜: 活动 交友 动画
查看: 868|回复: 1

深度处理图像填充块的做法

[复制链接]

2249

主题

2759

帖子

9603

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
9603
发表于 2021-11-4 09:32:13 | 显示全部楼层 |阅读模式
回复

使用道具 举报

2249

主题

2759

帖子

9603

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
9603
 楼主| 发表于 2021-11-4 09:32:34 | 显示全部楼层
仅使用Pil库进行图片处理,r通道高斯模糊设置模糊半径,g通道边缘检测并设置阈值0.5,b通道根据g通道计算闭合区域,并对闭合区域咦其中心y值(纹理坐标系)填色。

import os
from PIL import Image
from PIL import ImageFilter
dx=[-1,0,0,1]
dy=[0,-1,1,0]
xmin,ymin,xmax,ymax=[],[],[],[]
#思路:用PIL内置filter进行高斯模糊解决第一问
#用PIL内置filter进行边缘检测,遍历图片对每个纹素进行阈值判断解决第二问
#第三问:在边缘检测后的二值化图像求取闭合区域,通过深度优先搜索遍历黑色区域(非边缘部分)
#对每个连通分量进行标记,然后记录xmin,xmax,ymin,ymax得到连通块的bbox求取中心坐标
#栈模拟dfs防止溢出得不到结果,因为离线操作不太考虑时间效率。
class node:
    def __init__(self,x,y):
        self.x=x
        self.y=y
class Stack:
    def __init__(self):                        
            self.items = []
    def isEmpty(self):                        
            return self.items == []
    def push(self, item):                     
            self.items.append(item)
    def pop(self):                             
            return self.items.pop()
    def peek(self):                           
            return self.items[len(self.items)-1]
    def size(self):                           
            return len(self.items)
    def clear(self):                           
        self.items = []
#栈模拟dfs
def dfs(x,y,label,img):
    while(s.size()>0):
        cur=s.peek()
        flag[cur.x][cur.y]=label
        xmin[label-1]=min(xmin[label-1],cur.x)
        ymin[label-1]=min(ymin[label-1],cur.y)
        xmax[label-1]=max(xmax[label-1],cur.x)
        ymax[label-1]=max(ymax[label-1],cur.y)
        s.pop()
        for i in range(4):
            next=node(cur.x+dx,cur.y+dy)
            if(next.x<0 or next.y <0 or next.x>=width or next.y >=height): continue
            if(img.getpixel((next.x,next.y))==0 and flag[next.x][next.y]==0 ):
                s.push(next)
def threshold(t,img):
    for w in range(0,width):
        for h in range(0,height):
            pixel=float(img.getpixel((w,h)))/255
            if (pixel>t):
                img.putpixel((w,h),255)
            else:
                img.putpixel((w,h),0)
#记录相应的连通块及对应的bbox              
def connected(img):
    set=1
    xmin.append(width)
    ymin.append(height)
    xmax.append(0)
    ymax.append(0)
    for w in range(0,width):
        for h in range(0,height):
            if(img.getpixel((w,h))==0 and flag[w][h]==0):
                s.push(node(w,h))
                xmin.append(width)
                ymin.append(height)
                xmax.append(0)
                ymax.append(0)
                dfs(w,h,set,img)
                set+=1
#按bbox得到的中心坐标y值对其连通块填充颜色               
def fill(img):
    for w in range(0,width):
        for h in range(0,height):
            if(flag[w][h]>0):
                num=flag[w][h]-1
                cy=ymin[num]+(ymax[num]-ymin[num])/2
                cy=cy/height
                cy=int(cy*255)
                img.putpixel((w,h),cy)
if __name__ == '__main__':
    imgPath="D:/testD/F"
    newPath="D:/testD/F_n/"
    files=os.listdir(imgPath)
    for file in files:
        im=Image.open(imgPath+'/'+file)
        width=im.size[0]
        height=im.size[1]
        r,g,b,a=im.split()
        #第一问
        r=r.filter(ImageFilter.GaussianBlur(radius=3))
        g=g.filter(ImageFilter.FIND_EDGES)
        flag=[[0 for j in range(height)] for i in range(width)]
        s=Stack()
        #第二问
        threshold(0.5,g)
        b=g.copy()
        #第三问
        connected(b)
        fill(b)
        img=Image.merge("RGBA",[r,g,b,a])
        img.save(newPath+'/'+file,'png')
给定人物模型制作运动动画并进行物理渲染的线框效果展示。
制作思路:https://www.bilibili.com/read/cv3168157
TIM图片20191025140102.png-64kB

Shader "TestC/wireframe"
{
    Properties
    {
        [Toggle] _NoTriangle("NoTriangle",float)=0
        _wireThickness("wire thickness",Range(0,5))=0.05
        _wireColor("wire color",Color)=(1,1,1,1)
        _wireSmoothing("wire smoothing",Range(0,5))=1
    }
    SubShader
    {
        CGINCLUDE
        #include "UnityCG.cginc"
        #include "Lighting.cginc"
        fixed4 _wireColor;
        half _wireThickness;
        half _wireSmoothing;
        struct a2v{
            float4 vertexOSITION;
        };
        struct v2g
        {
            float3 vpos:TEXCOORD0;
            float4 wpos : SV_POSITION;
        };
        struct g2f
        {
            float3 vpos:TEXCOORD1;
            float4 pos : SV_POSITION;
            float3 barycentric:TEXCOORD0;
            float3 worldNormal:TEXCOORD2;
        };
        v2g vert (a2v v)
        {
            v2g o;
            o.vpos=v.vertex.xyz;
            o.wpos = mul(unity_ObjectToWorld,v.vertex);
            return o;
        }
        float3 getNormal(float3 pos0, float3 pos1,float3 pos2)
        {
            float3 a=pos1-pos0;
            float b=pos2-pos0;
            return normalize(cross(a,b));
        }
        [maxvertexcount(3)]
        void geom(triangle v2g p[3],inout TriangleStream<g2f> stream)
        {
            g2f o1,o2,o3;
            float3 param=float3(0,0,0);
            #if _NOTRIANGLE_ON
            float EdgeA = length(p[0].vpos - p[1].vpos);
            float EdgeB = length(p[1].vpos - p[2].vpos);
            float EdgeC = length(p[2].vpos - p[0].vpos);
            if(EdgeA > EdgeB && EdgeA > EdgeC)
                param.y = 1.;
            else if (EdgeB > EdgeC && EdgeB > EdgeA)
                param.x = 1.;
            else
                param.z = 1.;
            #endif
            o1.pos=mul(UNITY_MATRIX_VP,p[0].wpos);
            o2.pos=mul(UNITY_MATRIX_VP,p[1].wpos);
            o3.pos=mul(UNITY_MATRIX_VP,p[2].wpos);
            float3 triangleNomral=getNormal(p[0].wpos,p[1].wpos,p[2].wpos);
            o1.worldNormal=triangleNomral;
            o2.worldNormal=triangleNomral;
            o3.worldNormal=triangleNomral;
            o1.barycentric=float3(1,0,0)+param;
            o2.barycentric=float3(0,0,1)+param;
            o3.barycentric=float3(0,1,0)+param;
            o1.vpos=p[0].vpos;
            o2.vpos=p[1].vpos;
            o3.vpos=p[2].vpos;
            stream.Append(o1);
            stream.Append(o2);
            stream.Append(o3);
            stream.RestartStrip();
        }
        inline float aa1 (float threshold, float dist) {
            float delta = fwidth(dist) * _wireSmoothing;
            threshold=threshold*delta;
            return smoothstep(threshold-delta, threshold+delta, dist);
        }
        fixed4 fragfront (g2f i) : SV_Target
        {
            i.worldNormal=normalize(i.worldNormal);
            fixed3 ambient=UNITY_LIGHTMODEL_AMBIENT.xyz;
            fixed3 worldlight_dir=normalize(_WorldSpaceLightPos0.xyz);
            fixed3 diffuse=_LightColor0.rgb*_wireColor.rgb*saturate(dot(normalize(i.worldNormal),worldlight_dir));
            float3 barycentric=float3(i.barycentric.x,i.barycentric.y,i.barycentric.z);
            float thickness=_wireThickness;
            float d=min(barycentric.x,min(barycentric.y,barycentric.z));
            float t=1-aa1(thickness,d);
            return fixed4(ambient+diffuse,t);
        }
        ENDCG
        Pass
        {
            Tags{"Queue"="AlphaTest" "LightMode"="ForwardBase"}
            Cull front
            AlphaToMask On
            CGPROGRAM
            #pragma shader_feature _NOTRIANGLE_ON
            #pragma vertex vert
            #pragma fragment fragfront
            #pragma geometry geom
            #pragma target 4.0
            ENDCG
        }
        Pass
        {
            Tags{"Queue"="AlphaTest" "LightMode"="ForwardBase"}
            Cull back
            AlphaToMask On
            CGPROGRAM
            #pragma shader_feature _NOTRIANGLE_ON
            #pragma vertex vert
            #pragma fragment fragfront
            #pragma geometry geom
            #pragma target 4.0
            ENDCG
        }
    }
    FallBack "Diffuse"
}
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|starfluidga

GMT+8, 2024-12-21 01:00 , Processed in 0.015255 second(s), 20 queries .

Made by Liga 星鸿阁

Copyright © 2020-2048, LigaStudio.

快速回复 返回顶部 返回列表