Otaku Strokes Extractor v3 (OSE3)
概述
很久很久以前(大约20年7月)写的一个奇奇怪怪的算法,当时的目的是为了从一堆动漫图片中获取其线稿用于描画练习
但是当时还没有现如今流行的各种大模型,根本做不到快速的本地抽出,所以就去尝试了解了一下一些简单的图像处理库
(当时还在用7300HQ老U,做不到基于纯图形或者推测的处理),后来就想了个办法,用色容差和反色+灰度来解决这个问题,出来的效果也暂且不算难看,用于描画练习则是绰绰有余了。
最近翻出来了当时的V1和V2版本代码,仔细阅读后发现写的属实非常烂,就直接尝试对其进行了直接的整体重构
以下为代码,编译时请携带好STB的头,用clang -Os -o OSE3 OSE3.C -lm来执行编译
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "stb_image_write.h"
#define GRAYSCALE_RED_WEIGHT 0.3
#define GRAYSCALE_GREEN_WEIGHT 0.59
#define GRAYSCALE_BLUE_WEIGHT 0.11
void imgProcessGray(uint8_t *s, int sx, int sy, int stride, uint8_t *p, int gstride)
{
for (int y=0; y<sy; y++) {
for (int x=0; x<sx; x++) {
p[x] = GRAYSCALE_RED_WEIGHT * s[x*3+0] + GRAYSCALE_GREEN_WEIGHT * s[x*3+1] + GRAYSCALE_BLUE_WEIGHT *s[x*3+2];
}
s += stride*3;
p += gstride;
}
}
void imgProcessDilate(uint8_t *s, int w, int h, int k, uint8_t *p)
{
for (int y=1; y<h-1; y++) {
for (int x=1; x<w-1; x++) {
uint8_t uc = s[ (y+0)*w + (x+0) ];
uint8_t ua = s[ (y-1)*w + (x+0) ];
uint8_t ub = s[ (y+1)*w + (x+0) ];
uint8_t ul = s[ (y+0)*w + (x-1) ];
uint8_t ur = s[ (y+0)*w + (x+1) ];
uint8_t ux = 0;
if (uc > ux) ux = uc;
if (ua > ux) ux = ua;
if (ub > ux) ux = ub;
if (ul > ux) ux = ul;
if (ur > ux) ux = ur;
p[ y*w + x ] = ux;
}
}
}
void imgProcessAbsdiff(uint8_t *s, uint8_t *s2, int w, int h, uint8_t *p)
{
for (int n=0; n<w*h; n++) {
*p++ = abs(*s++ - *s2++);
}
}
void imgProcessReverse(uint8_t *s, int w, int h, uint8_t *p)
{
for (int n=0; n<w*h; n++) {
*p++ = 255 - *s++;
}
}
int main(int argc, char* argv[])
{
if (argc != 2) {
fprintf(stderr, "Otaku Strokes Extractor v3\n");
fprintf(stderr, "Usage: %s <image_path>\n", argv[0]);
return 1;
}
char *name = argv[1];
int w, h, bpp;
uint8_t *pixels = stbi_load(name, &w, &h, &bpp, 3);
if (!pixels) {
fprintf(stderr, "Failed to load image: %s\n", name);
return 1;
}
uint8_t *gray = (uint8_t*) malloc(w*h*4);
if (!gray) {
fprintf(stderr, "Failed to allocate memory for image processing.\n");
stbi_image_free(pixels);
return 1;
}
uint8_t *dilated = gray + w*h;
uint8_t *diff = dilated + w*h;
uint8_t *contour = diff + w*h;
printf("Processing %s...\n", name);
imgProcessGray(pixels, w, h, w, gray, w);
imgProcessDilate(gray, w, h, 5, dilated);
imgProcessAbsdiff(gray, dilated, w, h, diff);
imgProcessReverse(diff, w, h, contour);
stbi_write_jpg("result.jpg", w, h, 1, contour, 0);
printf("Done for %s !\n", name);
free(gray);
stbi_image_free(pixels);
return 0;
}
Windows体验版(使用MSYS2的gcc 11.3.0链静态构建)
OSE3_x64.exe
效果
原图
线稿
©版权所有者:クール教信者·双葉社/ドラゴン生活向上委員会