go 如何给数据库字段设置 null 值
写了个 patch 方法,因此我希望如果没有传入这个字段,则不更新这个字段的值,如果将这个字段显式设置为 null ,则将数据库的值更新为 null ,用指针的话好像也没办法区分 nil 和 null ,有什么好办法能解决这个问题吗?
写了个 patch 方法,因此我希望如果没有传入这个字段,则不更新这个字段的值,如果将这个字段显式设置为 null ,则将数据库的值更新为 null ,用指针的话好像也没办法区分 nil 和 null ,有什么好办法能解决这个问题吗?
最近一直都非常忙,所以连续 20 来天都没有碰过 Midjourney 了。前两天在社交媒体上看到,新推出的 V5.2 中有一个向外扩写的功能,因为此前已经在 PS+SD 的组合中见过这类拓展画面的应用思路,所以很想看看 MJ 的 Zoomout 能做出什么样的东西来。趁着端午假期这个空档,我集中跑了几波测试,有一些小小的心得,在此记录一下。
总体结论有三个:
1、Zoomout 可以无限次数地向外扩展,但随着镜头的拉远,Midjourney 自身的联想能力并不足以做出任何有意思的画面,不刻意控制地放大出来的画面,到了第 3~5 步之后,就会明显变得乏味和缺乏美感。
2、通过刻意地控制画幅比例、扩张倍数,以及针对性地调整 prompt 的描述,可以利用这个功能讲出有意思的故事。关键在于,使用者对于「镜头语言」的理解,以及对运镜和故事之间联系的掌控程度。
3、对工业设计的辅助甚微,做点「花活儿」可以,一旦涉及到逻辑,依旧不行。
测试内容目录:
1、通过默认的 Zoomout X2 按钮连续放大 3 次
2、通过默认的 Zoomout X2 按钮连续放大 15 次
3、通过自定义 Zoomout 微调构图
4、通过自定义 Zoomout 构建人物画像
5、通过自定义 Zoomout 构建人物性格
6、通过自定义 Zoomout 完善场景氛围
7、在 niji 中应用自定义 Zoomout 构建人物和场景
8、自定义 Zoomout 构建情绪与故事
9、通过焦点变化构建故事的场景
10、通过镜头变化,构建故事的起承转合
以下为部分测试过程记录:
test case no.1:通过默认的 Zoomout X2 按钮连续放大 3 次
操作方式:连续 3 次放大图像两倍,不对 prompt 进行修改,也不对画幅做设置。
输出成果:在奔跑的场景中增加了后方的人,有一点点故事性,但继续放大后会明显失焦,花面焦点始终在最开始的小女孩身上,继续放大生成的场景和人物都是模糊的。
test case no.2:通过默认的 Zoomout X2 按钮连续放大 15 次
点击以全屏查看图片 Click to view the image in full screen
操作方式:连续 15 次放大图像两倍,不对 prompt 进行修改,也不对画幅做设置。
输出成果:外围拓展的场景越宏大,有效信息和故事性就越低,除了在阴影中无意间冒出的人影,没有任何惊喜和意料之外,拓展的画面也很单调乏味。
test case no.3:通过自定义 Zoomout 微调构图
点击以全屏查看图片 Click to view the image in full screen
操作方式:不对 prompt 进行修改,按 1.1 和 1.2 的拓展比例小幅度调整画幅。
输出成果: 初始图像是近景特写,根据图像本身的特点,对画幅进行小幅度地微调来获得完整的全景镜头,以及合适的构图比例。
test case no.4:通过自定义 Zoomout 构建人物画像
点击以全屏查看图片 Click to view the image in full screen
操作方式:先生成一个黄色漩涡图案,然后拓展时改写 prompt 为一只眼睛,进而生成一个带特征的面部局部画面,再次拓展时修改描述词为一个洞穴中的原始部落男性。
输出成果: 成功构建了一个有目标特征「黄色漩涡瞳孔」的男性角色,通过控制拓展比例以达到最终效果—-人物整体和局部特征均得以完整呈现的画面。
test case no.5:通过自定义 Zoomout 构建人物性格
点击以全屏查看图片 Click to view the image in full screen
操作方式:先生成一个红色皮夹克的女性胸像,再改写 prompt 获得其坐在摩托车上的局部画面,再改写画幅比例获得完整的人物与车辆的全景照。
输出成果: 成功构建了一个有目标特征「红色皮衣+摩托车」的女性角色,通过控制拓展比例以达到最终效果—-人物细节和整体氛均衡的画面。
test case no.6:通过自定义 Zoomout 完善场景氛围
点击以全屏查看图片 Click to view the image in full screen
操作方式:在初次生成的几批图像中,选择合适的画风和画面主体,再根据已有画面特征修改画幅比例。
输出成果: 在选定风格和主体后,将竖幅主体拓展为气势更足的全景影像。关键是拓展比例并非默认的 2 倍或 1.5 倍,而是根据实际需求来控制比例,同时也需要关注怎样的画幅比例可以传达对应的氛围。最终图像画幅比例是 3:1,适合展现有足够细节的宽幅场景。
test case no.7:在 niji 中应用自定义 Zoomout 构建人物和场景
点击以全屏查看图片 Click to view the image in full screen
操作方式:
step 1、使用 niji 5 的 style original 生成一个细节丰富的初始人物;
step 2、以 1.2 的 Zoomout 比例纵向拓展出人物的半身画像,画幅比例是 1:2;
step 3、以 1.1 的 Zoomout 比例和 2:1 的画幅比例重构画面,得到外围场景;
step 4、以 1.2 的 Zoomout 比例和 3:4 的画幅比例重构画面,生成人物全身像;
step 5、改写 prompt 添加「宫殿」关键词,以 1.65 的 Zoomout 比例和 3:2 的画幅比例重构画面,生成人物在场景中的全景画面。
输出成果: 虽然人物细节和场景氛围的融合程度还不错,但因为漫画角色的细节较多,在多次 Zoomout 的过程中,场景的丰富会逐渐抢掉中心人物的视觉焦点。因此在每一次修改画幅比例与关键词的时候,需要多加注意对视觉元素的控制。
test case no.8:自定义 Zoomout 构建情绪与故事
点击以全屏查看图片 Click to view the image in full screen
操作方式:
step 1、生成一个情绪和神情符合目标的初始人物;
step 2、改写 prompt 同时添加「马」关键词,以 2 的 Zoomout 比例和 3:4 的画幅比例重构画面,生成后续画面的基础,此时需要注意人物与马的位置关系,否则后续生成的画面会非常扭曲怪异;
step 3、以 1.05 的 Zoomout 比例和 2:1 的画幅比例重构画面,生成完整的马匹造型与部份环境信息;
step 4、对比改写 prompt 产生的变化,黑发组不改描述词,以 1.1 的 Zoomout 比例和 3:4 的画幅比例重构画面;白发组添加「巨大镜子」关键词,以 1.6 的 Zoomout 比例和 3:4 的画幅比例重构画面。
输出成果:通过控制 Zoomout 的幅度、画幅比例和 prompt 的调整,可以生成指定场景的画面,且人物的神态到位、情绪饱满,整体画面焦点清晰。但美中不足是,构图不够自由。
test case no.9:通过焦点变化构建故事的场景
点击以全屏查看图片 Click to view the image in full screen
操作方式:
step 1、生成一个在河岸上的粽子;
step 2、修改 prompt 为「熊宝宝正准备吃粽子」,以 2 的 Zoomout 比例和 3:4 的画幅比例重构画面;
step 3、修改 prompt 为「小熊一家在野餐」,以 1.2 的 Zoomout 比例和 4:3 的画幅比例重构画面。
输出成果:通过对 prompt 的修改,控制 Zoomout 的幅度、画幅比例,可以改变画面中的焦点和表达主题,适合不同文化元素之间的混搭。
test case no.10:通过镜头变化,构建故事的起承转合
点击以全屏查看图片 Click to view the image in full screen
操作方式:
step 1、生成一幅鲜花山谷的画面,人物要明显;
step 2、修改 prompt 为「一面巨大的镜子在草地上」,以 2 的 Zoomout 比例和 3:4 的画幅比例重构画面,此处竖构图是为了生成较高的全身落地镜;
step 3、修改 prompt 为「少女站在镜子前」,以 1.5 的 Zoomout 比例和 3:2 的画幅比例重构画面,改为横构图是为了囊括少女全身以及环境信息。
输出成果:通过改变画面中的焦点和增加元素,在镜头逐渐拉远的过程中,故事缓缓托出。
我的整体感受是:
通过 Midjourney V5.2 的 Zoomout 无限拓展,一次次修改画幅比例、提示词内容,可以用镜头语言的变化来讲故事了,也可以基于一些初始的「点子」延展成有意思的融合作品。但越是这样,越发显得对话式、指令式的交互界面( SD 那种也不算图形交互 )的局限太大了,我很希望今年之内能发展出图形交互界面。
没错,今年 AI 的爆发指向了一个新的趋势:对话式交互界面。但人类之所以发明绘画,开始通过设计图来制作各式各样的新工具,恰恰就是因为语言本身的效率太低。这个逻辑其实也可以从媒体形态上找到端倪:文字–> 图像–> 视频。仅仅依靠对话,我们无法构建出一个一把剪刀;仅仅通过语言表达的播客,也无法传达任何需要视觉才可以精准理解的信息。对话指令的交互界面与图形交互界面之间的关系,并非只是 dos 和 windows 之间的差异,更重要的点在于,后者可以更直观地完成交互,以及精准地进行创作行为。AIGC 的重点不仅仅只是 AI,而是我们如何使用 AI 进行「Generative Content」。
我说一句话,AI 给我一个东西,这不是创作。
创作是一个生命在主观意志的驱使下,刻意的、有目的地表达其心中所想。
因为 GPT 的爆发而说对话式交互是未来,这样的断言是过于冲动的。只要是一个严肃的创作者,就会立刻意识到,真正的创作一定需要多纬度的交互界面。这其中不仅仅包含对话指令,同样更需要图形界面以及在数字虚拟空间中的三维交互。AIGC 工具与 PS、表格、PPT、思维导图等已有工具的结合,就是这类多维交互的雏形。
那一刻,我们不会等太久。
Midjourney V6 的质感和细节,真的是飞跃式的成长!
和今年三月相比,已经完全脱胎换骨了。对自然语言的理解和再表达,也已经在渐渐脱离「咒语」的局限,结合 ChatGPT 的语言转译,一个人能够用母语把尚不明确的观念表达清晰,愈发显得重要。
点击图片,可查看原始尺寸高清大图:
当 AI 越来越擅长理解人类的自然语言,我们就愈发迫切地要掌握「用语言表达思想」这件事情。
因为语言的精度和颗粒度,将会在人类与 AI 的相处、合作中,展现出人类智力的上限所在,以及外延的纵深能够得着多远。
在图像处理领域,我们会遇到如下需求:把图像中的目标物体和背景分开。比如背景用白色表示,目标物体用黑色表示。此时我们知道目标物体的灰度值相互接近,背景灰度值相互接近,那么用大津算法能很好把目标从背景当中区分开来。
比如对于下面这张灰度图片
目标物体是中间黑色的几何物体,我们想让这些物体和背景区分更明显一些,比如让物体为纯黑,背景全白。那么我们就需要找到一个合适的阈值,使图片上灰度值大于这个阈值的像素点为255(白色),灰度值小于阈值的像素点为0(黑色)。也就是变成下面这幅图:
那么大津算法需要处理的就是找到最佳的阈值,让目标和物体尽可能分离开。
为了找到合适的阈值,我们首先观察原图的灰度直方图📊:
这是用 Matlab 对原图形成的灰度直方图,灰度直方图的含义是统计图像中不同灰度值的分布情况。由图我们可以看出两个尖峰,在灰度值为0~20的地方存在一个尖峰,代表原图中有大量像素点灰度值为0~20,经观察我们可以认为这部分对应于目标物体。同理我们可以看出背景的灰度值大多集中于100~140之间,为了让目标和背景区分更加明显,我们想让目标物体的灰度值全为0,背景的灰度值全为255,这种处理手法也称为二值化法。
那么阈值取多少合适呢?从图上看似乎取50~100中的任意一点都可以,但是实际情况并不想参考图那样明显,有些图片背景和目标物体较为接近,我们需要一个算法来找到最优阈值才行。
首先我们思考什么样的东西才能成为一类,而我们又是怎么分类的。对于参考图来说,我们可以认为灰度值接近的为一类,灰度值不接近的不是同一类。那我们又是如何衡量灰度值接近的程度呢?这里面就需要用到方差的概念。
方差相比大家都了解,同一类的物体方差小,不同类的物体方差大。所以对于此图我们希望分类的结果是对于灰度值相近的同一类物体,它的方差最小,称为类内方差最小。灰度值不接近的不同类物体,它的方差大,称为类间方差最大。
所以步骤总结如下:
首先我们要形成参考图的灰度直方图,这样方便我们找到最佳阈值。
接下来我们通过穷举每一个灰度值,计算以此为阈值的类内和类间方差。
找到能形成类内方差最小的或类间方差最大的阈值,这个就是我们要找的最佳阈值。
下面以两类分割讲解下具体的算法,实际上大津算法可以分割多类出来。
因为 Medium 不支持显示 MathJax 语法的公式,所以对这部分感兴趣的直接移步到《大津算法(OTSU)》查看吧。
/* OTSU 算法
* *src 存储灰度图像,width 图像宽,height 图像长
* 返回最佳阈值
*/
int otsu(const int *src, int width, int height)
{
int histogram[256]; //存储灰度直方图,这里为256色灰度
int t,thred;
float wf,wb,ub,uf,curVal,maxVal;
int sumb=0,sumf=0,sumW=0,sumPixel=width*height;
wb=wf=maxVal=0.0f;
//求灰度直方图
memset(histogram,0,sizeof(histogram));
for(i=0;i<width*height;i++)
{
histogram[src[i]]++;
}
for (i=0;i<256;i++)
sumW+=i*histogram[i];
//枚举每个灰度
for(t=0;t<256;t++)
{
//求两类类概率密度
wb+=histogram[t];
wf=sumPixel-wb;
if (wb==0||wf==0)
continue;
//求类均值
sumb+=i*histogram[t];
sumf=sumW-sumb;
ub=sumb/wb;
uf=sumf/wf;
//求当前类间方差
curVal=wb*wf*(ub-uf)*(ub-uf);
if(curVal>maxVal)
{
thred=t;
maxVal=curVal;
}
}
return thred;
}