canvas简单实现纯色背景图片抠图(代码片段)

homehtml homehtml     2023-03-18     583

关键词:

最近在研究html5 canvas的过程中,发现,canvas为前端对图像的处理开辟了一条新的道路,canvas可以做到很多事情,甚至可以做个类似于PhotoShop的东西,曾经本人在一家软件工作就做类似的工作,可以看一下我之前开发的软件:
技术图片

这个就是canvas实现的类似于Adobe Photoshop,足以见得canvas的强大之处!

本文就是抽出其中一个小的功能点,来简单聊聊canvas强大之处:我们来一步步实现一个简单的智能抠图功能:(具体的代码见我的github:monkeyWangs/Matting)

1.环境准备

本人采用ES6语法作为开发环境,选用webpack作为构建工具,于是乎,我们有了webpack.config.js

/**
 * @author monkeyWang
 *
 */

/* 引入操作路径模块和webpack */
var path = require(‘path‘);
var webpack = require(‘webpack‘);

module.exports = 
  /* 输入文件 */
  entry: ‘./src/index.js‘,
  output: 
    /* 输出目录,没有则新建 */
    path: path.resolve(__dirname, ‘./dist‘),
    /* 静态目录,可以直接从这里取文件 */
    publicPath: ‘/dist/‘,
    /* 文件名 */
    filename: ‘matting.js‘
  ,
  module: 
    rules: [
      /* 用babel来解析js文件并把es6的语法转换成浏览器认识的语法 */
      
        test: /.js$/,
        loader: ‘babel-loader‘,
        /* 排除模块安装目录的文件 */
        exclude: /node_modules/
      
    ]
  

这样变准备好了开发用的基本环境,接下来我们来实现具体的核心代码,为了方便起见,我的代码全写在了inde.js

2.代码实现

首选我们需要新建一个对象:

/**
 * @author monkeywang
 * Date: 17/3/30
 */
class Matting 


然后我们需要接受用户上传的图片文件:

class Matting 
/**
   * 构造函数
   * @param file
   */
  constructor(file) 
    this.file = file
  

再接着把图片文件转成base64格式,所以我们在类中建了一个createStream方法:

createStream() 
let reader = new FileReader()
let ext = this.file.name.substring(this.file.name.lastIndexOf(".") + 1).toLowerCase()
if (ext != ‘png‘ && ext != ‘jpg‘ && ext != ‘jpeg‘) 
alert("图片的格式必须为png或者jpg或者jpeg格式!")
return
  
reader.onload = (e) => 
let src = e.target.result
    let img = new Image()
img.src = src
    let w = img.width
    let h = img.height
    this.fitch(w, h, img)
  
reader.readAsDataURL(this.file)

然后,开始我们的抠图逻辑代码之前,先描述一下我的思想:颜色属性其实是由RGBA四个元素组成的,RGB,代表三基色,A代表透明度,当A的值为0,则表示这个颜色是纯透明的,所以我们的主要逻辑就是把背景色设置为透明就好了。

创建一个canvas画布,然后把图片放到这个画布中,接着取这个图片上下左右四个点的像素,接下来要扣除这个图片的背景,那么,就需要去对整个图片的像素点颜色和背景色之前的区别,如果颜色相同,则把这个颜色的透明度设置成0

fitch(width, height, img) 
    let dataUrl
    let c = document.createElement("canvas")
    c.width = width
    c.height = height
    let ctx = c.getContext("2d")
    ctx.drawImage(img, 0, 0)
    /**
     * 取图片四个脚边的像素点rgba
     * @type *
     */
    let tl = Array.prototype.slice.call(ctx.getImageData(0, 0, 1, 1).data).join(‘,‘)
    let tr = Array.prototype.slice.call(ctx.getImageData(width - 1, 0, 1, 1).data).join(‘,‘)
    let br = Array.prototype.slice.call(ctx.getImageData(width - 1, height - 1, 1, 1).data).join(‘,‘)
    let bl = Array.prototype.slice.call(ctx.getImageData(0, height - 1, 1, 1).data).join(‘,‘)
    let imgdata = [tl, tr, bl, br] // 四个取色点
    let selfImageData = [] // 当前rgba
    imgdata.sort()
    // 目前只支持纯色背景抠图,简单的判断是否为纯色
    let deferNum = this.unique(imgdata).length
    if (deferNum <= 1) 
      
        selfImageData = imgdata[1].split(",") // 设置要扣除的主题色
        let isPNG = true // 判断是否已经扣过
        let imgDataUrl = ctx.getImageData(0, 0, width, height) //获取像素点
        let data = imgDataUrl.data
        for (let i = 0; i < data.length; i += 4) 
          // 得到 RGBA 通道的值
          let r = data[i]
          let g = data[i + 1]
          let b = data[i + 2]

          /**
           * function 判断颜色是不是属于背景色
           * @param numerical
           * @param index
           * @returns boolean
           */
          let isIn = (numerical, index) => 
            if (selfImageData[3] == 0) 
              isPNG = false
              return false
            
            return numerical > parseInt(selfImageData[index]) && numerical < parseInt(selfImageData[index])// 去掉边缘色
          

          if ([r, g, b].every(isIn)) 
            data[i + 3] = 0 // 设置背景透明
          
        
        // 将修改后的代码复制回画布中
        ctx.putImageData(imgDataUrl, 0, 0)
        dataUrl = c.toDataURL("image/png")
        if (isPNG) 
          /**
           * 创建下载链接 进行图片下载
           * @type Element
           */
          let a = document.createElement(‘a‘)
          a.href = dataUrl //下载图片
          a.download = ‘未命名.png‘
          a.click()
        
        else 
          alert(‘背景已抠除!‘)
        
      
    
    else 
      alert(‘只支持纯色背景抠图!‘)
    

  

然后我们测试一下效果:创建index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>
 <input type="file" id="file">
 <button onclick="matting()">开始抠图</button>
</body>
<script src="./dist/matting.js"></script>
<script>
  function matting() 
    var file = document.getElementById(‘file‘).files[0];
    var mat = new Matting(file);
    mat.createStream();
  
</script>
</html>

然后我们选择一个纯色背景图
技术图片

抠图后,我们看看:

技术图片

确实完成了抠图。

当然实现算法还不是很完善,主要是为了给大家展示canvas的无限可能,当然我也在逐步优化算法中,使得图片抠图更加完美,更加智能,也欢迎大家的star, pullrequest

一键智能抠图-原理实现(代码片段)

...可谓是非常精细了。有人说了,这张图片的的背景是简单的纯色背景,体现不出难度来。那我换一张我在路边拍的一朵不知名的 查看详情

快速实现一个简单的canvas迷宫游戏(代码片段)

...中并不常用,所以实践并不多,今天分享一下,如何实现简单canvas迷宫。这个例子来源于《html5秘籍》第二版,代码有稍微做了点调整。由于中间有一步使用canvas获取图片信息的时候,必须使用服务器环境。所以我先写了一个样... 查看详情

h5利用canvas实现海报功能(代码片段)

...上传图片生成海报。这个需求比较常规,实现思路也比较简单,通过利用用户的input输入,对所上传的图片进行处理,最后通过第三方库html2canvas合成对应的图片即可。思路虽然简单,但是在实现的过程中会遇到各种各样的小问... 查看详情

python+tkinter+canvas实现天降棒棒糖,生活甜甜蜜蜜(代码片段)

python+tkinter+canvas实现天降棒棒糖,生活甜甜蜜蜜。一、先看看效果吧。直接开始介绍了吧。二、准备资源图片通过ps或者ppt软件把这个图片抠图干净,就会出来的效果好看些。三、实现逻辑(一)自定义棒棒... 查看详情

python+tkinter+canvas实现天降棒棒糖,生活甜甜蜜蜜(代码片段)

python+tkinter+canvas实现天降棒棒糖,生活甜甜蜜蜜。一、先看看效果吧。直接开始介绍了吧。二、准备资源图片通过ps或者ppt软件把这个图片抠图干净,就会出来的效果好看些。三、实现逻辑(一)自定义棒棒... 查看详情

ai目标分割能力,无需绿幕即可实现快速视频抠图(代码片段)

...且不局限于特定的物体类别,在主体明确、背景相对简单 查看详情

android------开源的modnet算法实现抠图和更换背景(代码片段)

最近在研究图像出来这一块,网上查的比较多,试过基础的opencv的抠图,效果不是很理想opencv抠图参考https://blog.csdn.net/u010302327/article/details/78898781https://blog.csdn.net/hardWork_yulu/article/details/78757665试了很多ÿ 查看详情

canvas绘制双线技巧(代码片段)

...看这个问题,我在分析了项目背景的情况下,给予了一个简单的绘制技巧,就是先用较粗的线条绘制路径,然后再用较细的线条绘制路径,较细线条的颜色正好是背景颜色。之所以能够使用这个技巧,是因为该项目的绘制背景是... 查看详情

基于阿里semantatichumanmatting算法,实现精细化人物抠图(代码片段)

...、半身、全身位置,抠出人像部分后,配以不同背景图片、效果,实现娱乐化需求,支持用户玩转更多个性化操作,常用于直播、视频场景中。2018年阿里的论文《SemantaticHumanMatting》给出了抠图领域的一个新方... 查看详情

python几行代码实现一键抠图,收费应用byebye(代码片段)

⛳️需求来源好友A:橡皮擦,可否提供网页,上传带人像的图片,然后可以直接抠图,最好直接生成PNG图片下载。橡皮擦:每天需要调用多少次?好友A:大概100次吧。橡皮擦:妥了,给你写个免费的吧。本案例的实战需求是对... 查看详情

不惧繁杂背景,视频编辑服务一键实现人像抠图(代码片段)

最近,“你这背景太假了”席卷全网。由于身后风景太优美,被网友质疑背景太假,某主播为了自证,直接把手里的桶扔进了背后的水里。短短几天时间播放量几十亿,引发了全网P图狂潮,网友在短视频Ap... 查看详情

不惧繁杂背景,视频编辑服务一键实现人像抠图(代码片段)

最近,“你这背景太假了”席卷全网。由于身后风景太优美,被网友质疑背景太假,某主播为了自证,直接把手里的桶扔进了背后的水里。短短几天时间播放量几十亿,引发了全网P图狂潮,网友在短视频Ap... 查看详情

使用canvas实现交互性圆形马赛克效果(代码片段)

...端无法把玩,于是就自己实现了一个canvas版本的。代码很简单,canvas初学者可以自己试试当做练笔,还是挺有趣的一个效果。OnlineDemoonlinedemo在demo中任意从本地选择一张图片,然后通过鼠标移动或者移动端touchmove就能实现圆形分... 查看详情

swift抠图功能

...抠出来,通常有两种办法:(1)使用CoreImage色域:适合纯色背景(或者背景色相对单一,色差不会太大),抠图精准(2)使用openCv边缘检测:复杂背景情况也适用,默认抠图不够精确如何使用CoreImage抠图对于纯色背景,可以直... 查看详情

canvas实现验证码功能(代码片段)

...后端接口,前端使用canvas直接生成验证码。由于功能过于简单,不需要多少代码和文字说明,下面直接贴出代码。1、代码<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><ti 查看详情

python案例用某度ai接口实现抠图并改图片底色(代码片段)

...文一、注册百度AI账号,创建人像分割应用二、代码实现1.引入库2.获取AccessToken核心代码4.图片底色填充5.图片压缩6.获取图图片大小7.png格式转jpg8.主函数9.完整代码[重要]使用前注意事项最终效果图总结前言嗨嗨,大家好... 查看详情

python几行代码实现一键抠图,收费应用byebye(代码片段)

⛳️需求来源好友A:橡皮擦,可否提供网页,上传带人像的图片,然后可以直接抠图,最好直接生成PNG图片下载。橡皮擦:每天需要调用多少次?好友A:大概100次吧。橡皮擦:妥了,给你... 查看详情

canvas实现刮刮卡效果(代码片段)

canvas实现刮刮卡效果实现步骤:设置页面背景图,即刮刮卡底部图片绘制canvas刮刮卡顶部图片drawImage绑定事件addEventListener touchstart、touchmove完整代码:1<!DOCTYPEhtml>2<html>3<head>4<metacharset="utf-8">5<metaname="v 查看详情