查看原文
其他

码区不大,创造神话,科目三杀进来了

代雨童、马丽 OSC开源社区 2024-01-10




前言


作为 Go 后端的唯一妹纸实习生,Boss 听说我之前跳过舞,实习第一天让我跳个程序员版本科目三,帮忙宣传一波,00 后整顿职场不能怂,被我义正严辞地拒绝了。


没想到过了一个小时,老板发了个红包。

人间疾苦,有钱无阻,老板,你看人真准。自己跳是不可能的,咱来个“曲线救国”让 Excel 替我跳一个科目三。
如何实现让 Excel 跳科目三呢?经过一番秃头研究👨‍🦲,想到视频都是由连续的图片组成,想要实现在 Excel 中跳舞那就需要多张连续的图片,只要找一个科目三舞蹈视频通过转换为连续的图片并将图片导入 Excel ,然后使用 Chromeless 截取个几百张图最后组装就能生成舞蹈视频啦。
但是只插入图片未免太过无趣,网上搜罗一圈发现图片还能转 ASCII 字符集,且导入 Excel 方案可行,这就开干!




视频转图片


首先是保存一个科目三的舞蹈视频,这里从各大视频网站中可以获取。从 Chrome 应用商店里白嫖一个下载插件,再白嫖一个科目三视频。
最后,使用 ffmpeg 这个强大的视频流处理工具来获取指定帧数的图片。
官网下载地址:https://ffmpeg.org/download.html
从目标.mp4 视频文件中提取图像帧,每秒提取 15 帧,输出的图像文件名格式为三位数字.jpg
ffmpeg -i 目标.mp4 -r 15 %3d.jpg
运行结果如下:




图片转 ASCII 字符集


重头戏之一来了,在线的转换工具倒是有不少,效果也不错👇
在线转换网站地址:https://neucrack.com/tools/ascii
但是一秒的视频至少 15 张图片,十秒就是 150 张一个一个手动转换和手动导入 Excel 会夭寿的。
作为计算机专业出身,代码编写少不了,使用 Go 语言实现以上功能,流程图如下:
这里使用广泛使用的 "github.com/fogleman/gg" 和 "github.com/nfnt/resize" 图形处理库来进行图片的缩放以及像素获取
func processPixel(context *gg.Context, file *excelize.File, h, w int) { //获取像素点颜色 pixelColor := context.Image().At(w, h) r, g, b, _ := pixelColor.RGBA() //获取像素点亮度值 pixelValue, _, _ := color.RGBToYCbCr(uint8(r/256), uint8(g/256), uint8(b/256)) asciiIndex := int((float64(pixelValue) / 255) * float64(len(asciiChars)-1)) asciiChar := string(asciiChars[asciiIndex]) weight := asciiWeights[asciiIndex] fontColor := fmt.Sprintf("%02X%02X%02X", int(r/256), int(g/256), int(b/256)) result := strings.Repeat(asciiChar, int(weight)) cell := fmt.Sprintf("%s%d", columnIndexToExcelName(w), h+1) file.SetCellValue(sheetName, cell, result) style, _ := file.NewStyle(&excelize.Style{ Font: &excelize.Font{ Color: fontColor, //字体颜色 }, Border: []excelize.Border{}, //空切片无边框 }) file.SetCellStyle(sheetName, cell, cell, style)}
映射方法:

在 RGB 色彩模型中,亮度的取值通常与颜色的亮度成正比。在这里,pixelValue 是从图像中提取的像素的亮度值。对于 RGB 色彩模型,可以通过以下公式将 RGB 值转换为亮度值:亮度值=0.299×R+0.587×G+0.114×B


这里,R、G、B 分别是像素的红、绿、蓝分量。这个公式是一种常见的计算灰度值的方法,其中每个颜色分量的权重反映了人眼对不同颜色的感知。在这种情况下,亮度值的范围通常是 [0, 255],其中 0 表示黑色,255 表示白色。


通常情况下,亮度值越大,表示像素的颜色越接近白色,亮度越小,表示颜色越接近黑色。在上述代码中,pixelValue 的值被归一化到范围 [0, 1],用于确定在 ASCII 字符集中选择哪个字符。

例如,根据自定义的 ASCII 字符集和权重:
-asciiChars="@%#*+=-" -weights="15,10,7,5,3,2,1"
亮度越大的值归一化后越接近 1,对应的字符索引越大,亮度越小的值归一化后越接近 0,对应的字符索引越小,255 白色亮度对应索引 index=len(asciiChars)-1 即转换后显示 1 个-字符,0 亮度黑色对应索引 index=0 即转换后显示 15 个@字符。




ASCII 字符集导入 Excel


这里使用 github.com/xuri/excelize/v2 库来进行 Excel 处理,进行单元格行列高列宽设置,单元格内容填充,并行处理像素点,最后保存 Excel 文件。
func imageToASCII(imagePath, outputExcel string) { context, err := openAndResizeImage(imagePath, scaleFactor) if err != nil { fmt.Println(err) return } //获取像素大小 imgWidth, imgHeight := context.Image().Bounds().Dx(), context.Image().Bounds().Dy() file, _, err := createExcelFile() if err != nil { fmt.Println(err) return } //设置单元格大小 setColumnWidths(file, imgWidth) setRowHeights(file, imgHeight) for h := 0; h < imgHeight; h++ { wg.Add(1) //并行处理每行像素点 go func(h int) { defer wg.Done() for w := 0; w < imgWidth; w++ { processPixel(context, file, h, w) } }(h) } // 等待所有 goroutine 完成 wg.Wait() // 保存 Excel 文件 if err := file.SaveAs(outputExcel); err != nil { fmt.Println("Error saving Excel file:", err) } else { fmt.Println("Excel file saved") }}




运行示例


  1. 以默认设置启动

  1. 通过命令行参数自定义运行

参数解释如下图:go run ascii.go -h
go run ascii.go -asciiChars="@%#*+=-:." -weights="15,10,7,5,3,2,1,0.5,0.1" 




图片转视频


用程序将 excel 导入到石墨文档,在使用 chromedp 截图,最终使用 ffmpeg 转为每秒 15 帧的视频,然后播放,大功告成!
ffmpeg -r 15 -pattern_type glob -i '截屏*.png' video1.mp4
播放:ffplay video1.mp4




总结


到此,介绍了利用 Go 语言和一些开源库实现的一个有趣项目,通过将图片转换为 ASCII 字符,并将结果保存到 Excel 文件中,最终实现 Excel 版科目三视频。支持自定义字符集和权重以及图片缩放大小来实现不同的视觉效果。同时项目的不足之处在于处理大型图片时性能可能较差,可以考虑优化算法或者优化并行处理,后续也可以支持选择不同的图片转换方式,例如像素图等。希望通过分享这个项目,能够激发更多人对图形处理和代码创意的兴趣。
最后附上参考资料以及完整的源码地址:
  • 完整的源码:https://github.com/shimo-open/ascii-to-excel
  • fogleman/gg官方文档:https://pkg.go.dev/github.com/fogleman/gg
  • github地址:https://github.com/qax-os/excelize 
  • ffmpeg官网下载:https://ffmpeg.org/download.html



更多玩法等你体验: 

 

 


往期推荐




支持苹果芯片的Fedora发行版来了!Linus看了会狂喜

因躁狂症失业,知名开源项目作者“在线求打钱”

No Star, No Fix




这里有最新开源资讯、软件更新、技术干货等内容

点这里 ↓↓↓ 记得 关注✔ 标星⭐ 哦


继续滑动看下一个

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存