使用 Javascript 将油画/素描效果应用于照片

2023-12-24

我想使用javascript从照片开始模拟人体绘图效果。

我一直在搜索几个进行图像处理的 js 库(主要是在画布上)。 但似乎没有人尝试过我正在寻找的东西。

我认为用javascript实现这样的效果并不是不可能的。所以我想知道为什么我找不到任何已经完成的事情。

在本机方面,有几种 Photoshop 的替代方法可以实现此类效果,如 App Store 中的几个应用程序所示:

  • 油画展位免费 https://itunes.apple.com/it/app/oil-painting-booth-free-best/id486172126?mt=8
  • 一笔 http://www.pastemagazine.com/articles/2014/03/brushstroke-app-turns-your-photos-into-lovely-pain.html
  • 自动喷漆师 https://itunes.apple.com/IT/app/id429133097?mt=8
  • 艺术家的触感 https://itunes.apple.com/IT/app/id298606069?mt=8
  • 亲笔签名 https://itunes.apple.com/IT/app/id442567684?mt=8

以下是可能结果的其他示例(来自 Artist's Touch 应用程序):


好吧,我找到了所用算法的很好的解释here http://www.codeproject.com/Articles/471994/OilPaintEffect并对其进行了JS和canvas的适配。

现场演示 http://jsfiddle.net/loktar/96arS/

CodePen 演示,带有控件来扰乱效果 http://codepen.io/loktar00/full/Fhzot/

它的工作原理是对中心像素周围的所有像素进行平均,然后将该平均值乘以所需的强度级别,然后除以 255。然后递增与强度级别相关的 r/g/b。然后检查相邻像素中哪个强度级别最常见,并将该强度级别分配给目标像素。

edit做了更多的工作并重写了很多内容,获得了一些非常巨大的性能提升,现在可以很好地处理大小合适的图像。

var canvas = document.getElementById("canvas"),
    ctx = canvas.getContext("2d"),
    img = new Image();

img.addEventListener('load', function () {
    canvas.width = this.width;
    canvas.height = this.height;
    ctx.drawImage(this, 0, 0, canvas.width, canvas.height);
    oilPaintEffect(canvas, 4, 55);
});

img.crossOrigin = "Anonymous";
img.src = "https://fbcdn-sphotos-h-a.akamaihd.net/hphotos-ak-xpa1/v/t1.0-9/1379992_10202357787410559_1075078295_n.jpg?oh=5b001e9848796dd942f47a0b2f3df6af&oe=542F3FEF&__gda__=1412145968_4dbb7f75b385770ecc3f4b88105cb0f8";

function oilPaintEffect(canvas, radius, intensity) {
    var width = canvas.width,
        height = canvas.height,
        imgData = ctx.getImageData(0, 0, width, height),
        pixData = imgData.data,
        destCanvas = document.createElement("canvas"),
        dCtx = destCanvas.getContext("2d"),
        pixelIntensityCount = [];

    destCanvas.width = width;
    destCanvas.height = height;

    // for demo purposes, remove this to modify the original canvas
    document.body.appendChild(destCanvas);

    var destImageData = dCtx.createImageData(width, height),
        destPixData = destImageData.data,
        intensityLUT = [],
        rgbLUT = [];

    for (var y = 0; y < height; y++) {
        intensityLUT[y] = [];
        rgbLUT[y] = [];
        for (var x = 0; x < width; x++) {
            var idx = (y * width + x) * 4,
                r = pixData[idx],
                g = pixData[idx + 1],
                b = pixData[idx + 2],
                avg = (r + g + b) / 3;

            intensityLUT[y][x] = Math.round((avg * intensity) / 255);
            rgbLUT[y][x] = {
                r: r,
                g: g,
                b: b
            };
        }
    }


    for (y = 0; y < height; y++) {
        for (x = 0; x < width; x++) {

            pixelIntensityCount = [];

            // Find intensities of nearest pixels within radius.
            for (var yy = -radius; yy <= radius; yy++) {
                for (var xx = -radius; xx <= radius; xx++) {
                    if (y + yy > 0 && y + yy < height && x + xx > 0 && x + xx < width) {
                        var intensityVal = intensityLUT[y + yy][x + xx];

                        if (!pixelIntensityCount[intensityVal]) {
                            pixelIntensityCount[intensityVal] = {
                                val: 1,
                                r: rgbLUT[y + yy][x + xx].r,
                                g: rgbLUT[y + yy][x + xx].g,
                                b: rgbLUT[y + yy][x + xx].b
                            }
                        } else {
                            pixelIntensityCount[intensityVal].val++;
                            pixelIntensityCount[intensityVal].r += rgbLUT[y + yy][x + xx].r;
                            pixelIntensityCount[intensityVal].g += rgbLUT[y + yy][x + xx].g;
                            pixelIntensityCount[intensityVal].b += rgbLUT[y + yy][x + xx].b;
                        }
                    }
                }
            }

            pixelIntensityCount.sort(function (a, b) {
                return b.val - a.val;
            });

            var curMax = pixelIntensityCount[0].val,
                dIdx = (y * width + x) * 4;

            destPixData[dIdx] = ~~ (pixelIntensityCount[0].r / curMax);
            destPixData[dIdx + 1] = ~~ (pixelIntensityCount[0].g / curMax);
            destPixData[dIdx + 2] = ~~ (pixelIntensityCount[0].b / curMax);
            destPixData[dIdx + 3] = 255;
        }
    }

    // change this to ctx to instead put the data on the original canvas
    dCtx.putImageData(destImageData, 0, 0);
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 Javascript 将油画/素描效果应用于照片 的相关文章

随机推荐

  • SQL Server XML 添加属性(如果不存在)

    我正在尝试添加一个属性 如果它不存在 它应该很简单 但我对 XML XPath XQuery 等还不熟悉 所以请原谅我的无知 我希望能够传递 XML 数据并修改它 ALTER FUNCTION dbo ConvertXmlData xmlD
  • Kendo UI 网格插入/更新(再次)创建重复记录

    我在这个主题中遇到了与丹尼尔相同的问题 但他的解决方案对我不起作用 http www kendoui c om forums ui grid kendo ui grid inserts updates create duplicate re
  • Gmail 中添加了一个间隙,位于 Outlook 的 html 签名内

    我创建了一个需要在 Outlook 中使用的 html 签名 根据建议 我使用了表格布局 给定所有图像 甚至 td tr 和表格本身的特定高度和宽度 0 填充和边距 甚至尝试在 css 和旧式方式中添加这些内容实际标签 在 Outlook
  • 如何使用 LibGit2Sharp 向 VSTS 进行身份验证?

    我正在尝试使用 LibGit2Sharp 克隆 VSTS Visual Studio Team Services 存储库 我正在设置一个CredentialsHandler and UsernamePasswordCredentials代表
  • Primefaces 保存/传递过滤后的数据表结果列表

    目前 我正在使用具有排序 过滤功能的数据表成功地显示数据库中的图像元数据 在我的数据表下方 我使用第三方图像封面成功地显示了我的图像 http www jacksasylum eu ContentFlow http www jacksasy
  • 引导日期选择器

    我试图让引导日期选择器突出显示在下拉日期选择器中选择的日期 它目前没有这样做 我错过了什么 div class input append date div
  • 根据控制器中的变量显示或隐藏元素 - Ionic

    据我所知 这可能更多的是 AngularJS 问题 而不是 Ionic 特定问题 我的一个视图中有一个按钮
  • 获取个人应用代码并显示

    我正在尝试获取应用程序代码并显示它 例如 如果按钮 X 启动一个新活动 则 textView 显示整个方法 我只到达了如何以 HTML 格式显示代码这个问题 https stackoverflow com questions 1529068
  • 跟踪电子中的窗口大小

    我今天才开始玩 Electron 我需要能够获取可用的窗口大小 并在窗口大小调整时更新它 看起来这并不像传统的 JS 应用程序那么简单 跟踪窗口大小的推荐方法是什么 目前 我有我的主进程和一个渲染器 不打算一次打开超过 1 个渲染器 窗口
  • 如何从命令行发送电子邮件?

    我想从命令行快速发送电子邮件 我意识到可能有多种不同的方法可以做到这一点 我正在寻找一种从 Linux 终端 可能是 bash shell 但任何东西都可以 执行此操作的简单方法 以及在 Windows 上执行此操作的替代方法 我希望能够直
  • 如何在 UML 序列图中表示监听器

    在序列图中 如何表示事件触发的侦听器 它不仅仅是常规方法调用 因此这样显示似乎不正确 我尝试制作包含 JMS 侦听器的系统的序列图 我可以通过系统对 JMS 队列的 send 调用来启动生命线 将调用 send 的系统显示为业务参与者 或者
  • Django 克隆递归对象

    以前 当我想递归地克隆对象时 我遇到了问题 我知道克隆对象的简单方法是这样的 obj Foo objects get pk
  • Swift 中何时使用静态常量和变量?

    有一些帖子介绍如何编写代码static constant and static variable在斯威夫特 但不清楚什么时候使用static constant and static variable而不是constant and varia
  • (InvalidRequestException) 调用 GetQueryResults 时...从 Lambda Python 查询 Athena...无法读取结果

    我一直在尝试从我的 lambda 函数 Python3 8 查询 Athena 但尽管尝试添加 if else 语句来检查执行状态 但我不断收到相同的错误 并且在 aws 控制台和 cli 上总是出现相同的错误本地 这是 lambda 函数
  • 根据用户用于浏览的设备(android tab、iphone、ipad)动态更改 zend 中的布局和模板

    我正在开发一个应用程序 PC 杂志商店 我已经完成了 PC 的大部分工作 但客户端也希望在其他 Android 设备上有同样的东西 作为 Web 视图加载 由于这些设备的高度和宽度与PC不同 所以我需要以最简单的方式获取设备的尺寸和高度 以
  • 我也应该连接到 QNetworkReply::error() 吗?

    我创建了一个 POST 请求并连接到完成的 http qt project org doc qt 5 0 qtnetwork qnetworkreply html finished signal QNetworkReply reply ma
  • 从 Uri 打开文件,与 Android 中的位置无关

    我可以使用一些帮助来了解如何在 android 中打开文件 我的具体问题与打开图像文件有关 在我的应用程序中 用户使用他们选择的相机应用程序拍摄图像 然后我对返回的图像进行操作 根据手机 Android 版本和所选相机应用程序的不同 我会在
  • javascript正则表达式从字符串末尾到开头搜索

    是否可以使用正则表达式从字符串末尾到开头进行搜索 例如我有一个字符串 a2bba2b 我知道我需要最后一次出现 a2 并且让机器遍历可能很长的整个字符串似乎效率非常低 我知道针将位于字符串 haystack 末尾附近的某个位置 所以我想颠倒
  • 显示特定产品类别的 WooCommerce 购物车项目简短描述

    在 WooCommerce 中 我尝试添加购物车项目中特定类别的产品简短描述 I found 这段代码 https stackoverflow com questions 27900033 solution for short descri
  • 使用 Javascript 将油画/素描效果应用于照片

    我想使用javascript从照片开始模拟人体绘图效果 我一直在搜索几个进行图像处理的 js 库 主要是在画布上 但似乎没有人尝试过我正在寻找的东西 我认为用javascript实现这样的效果并不是不可能的 所以我想知道为什么我找不到任何已