@darkproject
2020-02-13T11:30:12.000000Z
字数 5107
阅读 1116
记录
5道选2道做,自身美术实力的确还需要加强。有道比较不错的程序化建模题(待补中,打算用houdini和引擎内各实现一遍)。花了1天时间学习了py语法和pil库(查资料累死咯)据说第三问可以直接用pil库做,不过没有找到相关api,自身结合竞赛图论知识勉强怼了出来。
仅使用Pil库进行图片处理,r通道高斯模糊设置模糊半径,g通道边缘检测并设置阈值0.5,b通道根据g通道计算闭合区域,并对闭合区域咦其中心y值(纹理坐标系)填色。
import osfrom PIL import Imagefrom PIL import ImageFilterdx=[-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=xself.y=yclass 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 = []#栈模拟dfsdef dfs(x,y,label,img):while(s.size()>0):cur=s.peek()flag[cur.x][cur.y]=labelxmin[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[i],cur.y+dy[i])if(next.x<0 or next.y <0 or next.x>=width or next.y >=height): continueif(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)))/255if (pixel>t):img.putpixel((w,h),255)else:img.putpixel((w,h),0)#记录相应的连通块及对应的bboxdef connected(img):set=1xmin.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]-1cy=ymin[num]+(ymax[num]-ymin[num])/2cy=cy/heightcy=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
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 vertex:POSITION;};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_ONfloat 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.;elseparam.z = 1.;#endifo1.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);}ENDCGPass{Tags{"Queue"="AlphaTest" "LightMode"="ForwardBase"}Cull frontAlphaToMask OnCGPROGRAM#pragma shader_feature _NOTRIANGLE_ON#pragma vertex vert#pragma fragment fragfront#pragma geometry geom#pragma target 4.0ENDCG}Pass{Tags{"Queue"="AlphaTest" "LightMode"="ForwardBase"}Cull backAlphaToMask OnCGPROGRAM#pragma shader_feature _NOTRIANGLE_ON#pragma vertex vert#pragma fragment fragfront#pragma geometry geom#pragma target 4.0ENDCG}}FallBack "Diffuse"}