麻豆小视频在线观看_中文黄色一级片_久久久成人精品_成片免费观看视频大全_午夜精品久久久久久久99热浪潮_成人一区二区三区四区

首頁 > 開發 > HTML5 > 正文

html5利用canvas實現顏色容差摳圖功能

2024-09-05 07:23:11
字體:
來源:轉載
供稿:網友

利用canvas的getImageData,我們可以獲取到一張圖片每一個像素的信息,而通過對每一個像素信息的對比,我們就可以找到需要消去的像素點。比如下面這一張圖片,如果我們想要扣去白色部分(粉色是body的背景顏色)。

 

let canvas = document.querySelector('#canvas');let context = canvas.getContext('2d');let img = document.createElement('img');img.src = './head2.png';img.onload = function () {    canvas.height = img.height;    canvas.width = img.width;    context.drawImage(img, 0, 0);    cutout(canvas, [255, 255, 255], 0.2); // 對白色進行摳除,容差為0.2}function cutout(canvas, color, range = 0) {    let context = canvas.getContext('2d');    let imageInfo = context.getImageData(0, 0, canvas.width, canvas.height);    // pixiArr是一個數組,每四個數組元素代表一個像素點,這四個數組元素分別對應一個像素的r,g,b,a值。    let pixiArr = imageInfo.data;    for (let i = 0; i < pixiArr.length; i += 4) {    // 匹配到目標像素就將目標像素的alpha設為0        if (testColor([pixiArr[i], pixiArr[i + 1], pixiArr[i + 2]], color, range)) pixiArr[i + 3] = 0;    }    context.putImageData(imageInfo, 0, 0);}function testColor(current, target, range) {    for (let i = 0; i < 3; i++) {        if (!((1 - range) * target[i] <= current[i] && (1 + range) * target[i] >= current[i])) return false;    }    return true;}

 

testColor(current, target, range) 方法三個參數分別為 待檢測像素點的rgb數組 、 目標像素點的rgb數組 和 容差范圍 ,這里的容差只是簡單用r、g、b的值分別乘以(1 + range)和(1 - range)來計算并對比,不同的容差參數會得到不同的效果↓

range = 0.095

 

range = 0.1

 

range = 0.2

 

當然對于底色是標準的純色的圖片就不需要容差了。

邊界處理

但是有時候我們希望有一個邊界,讓摳圖操作不對邊界內部的像素造成影響。比如上面的圖片,我們希望不會對人物頭像內部的像素造成影響。 如果我們一行一行來看,是不是只要在碰到不是邊界像素的時候停止操作,就可以達到效果了呢?

我們對每一行分別進行掃描,定義一個左指針 left 指向這一行的第一個像素,定義一個右指針 right 指向這一行的最后一個像素,并用一個 leftF 標識左邊是否碰到邊界,一個 rightF 標識右邊是否碰到邊界,當沒碰到邊界時指針就一直向內收縮,直到兩個指針都碰到邊界或者左右指針重合就跳到下一行,直到所有行都掃描完畢。

function cutout(canvas, color, range = 0) {    let context = canvas.getContext('2d');    let imageInfo = context.getImageData(0, 0, canvas.width, canvas.height);    let pixiArr = imageInfo.data;    for (let row = 0; row < canvas.height; row++) {        let left = row * 4 * canvas.width; // 指向行首像素        let right = left + 4 * canvas.width - 1 - 3; // 指向行尾像素        let leftF = false; // 左指針是否碰到邊界的標識        let rightF = false; // 右指針是否碰到邊界的標識        while (!leftF || !rightF) { // 當左右指針都為true,即都碰到邊界時結束            if (!leftF) {                if (testColor([pixiArr[left], pixiArr[left + 1], pixiArr[left + 2]], color, range)) {                    pixiArr[left + 3] = 0; // 此像素的alpha設為0                    left += 4; // 移到下一個像素                } else leftF = true; // 碰到邊界            }            if (!rightF) {                if (testColor([pixiArr[right], pixiArr[right + 1], pixiArr[right + 2]], color, range)) {                    pixiArr[right + 3] = 0;                    right -= 4;                } else rightF = true;            }            if (left == right) { // 左右指針重合                leftF = true;                rightF = true;            };        }    }    context.putImageData(imageInfo, 0, 0);}

 

雖然大概完成了我們的需求,但是看一下上面頭發那為啥會多了一塊白色

 

因為我們僅僅只進行了行掃描,當左指針碰到頭發時就會停止掃描,但是頭發弧度里面的就無法被掃描到了,我們還需要進行列掃描,改造一下上面的方法:

function cutout(canvas, color, range = 0) {    let context = canvas.getContext('2d');    let imageInfo = context.getImageData(0, 0, canvas.width, canvas.height);    let pixiArr = imageInfo.data;    for (let row = 0; row < canvas.height; row++) {        let left = row * 4 * canvas.width;        let right = left + 4 * canvas.width - 1 - 3;        let leftF = false;        let rightF = false;        while (!leftF || !rightF) {            if (!leftF) {                if (testColor([pixiArr[left], pixiArr[left + 1], pixiArr[left + 2]], color, range)) {                    pixiArr[left + 3] = 0;                    left += 4;                } else leftF = true;            }            if (!rightF) {                if (testColor([pixiArr[right], pixiArr[right + 1], pixiArr[right + 2]], color, range)) {                    pixiArr[right + 3] = 0;                    right -= 4;                } else rightF = true;            }            if (left == right) {                leftF = true;                rightF = true;            };        }    }    // 同理進行列掃描    for (let col = 0; col < canvas.width; col++) {        let top = col * 4; // 指向列頭        let bottom = top + (canvas.height - 2) * canvas.width * 4 + canvas.width * 4; // 指向列尾        let topF = false;        let bottomF = false;        while (!topF || !bottomF) {            if (!topF) {                if (testColor([pixiArr[top], pixiArr[top + 1], pixiArr[top + 2]], color, range)) {                    pixiArr[top + 3] = 0;                    top += canvas.width * 4;                } else topF = true;            }            if (!bottomF) {                if (testColor([pixiArr[bottom], pixiArr[bottom + 1], pixiArr[bottom + 2]], color, range)) {                    pixiArr[bottom + 3] = 0;                    bottom -= canvas.width * 4;                } else bottomF = true;            }            if (top == bottom) {                topF = true;                bottomF = true;            };        }    }    context.putImageData(imageInfo, 0, 0);}

 

至于top和bottom為啥是那樣計算畫個矩陣圖大概就知道了。

 

處理后↓

 

其實還可以先將 pixiArr 包裝為以一個像素點為單位的矩陣

[    [{r: 255, g: 255, b: 255, a: 1}, {r: 255, g: 255, b: 255, a: 1}, {r: 255, g: 255, b: 255, a: 1}],    [{r: 255, g: 255, b: 255, a: 1}, {r: 255, g: 255, b: 255, a: 1}, {r: 255, g: 255, b: 255, a: 1}]    [{r: 255, g: 255, b: 255, a: 1}, {r: 255, g: 255, b: 255, a: 1}, {r: 255, g: 255, b: 255, a: 1}]]

處理后計算像素下標也就會更簡單,列掃描時直接先將這個矩陣旋轉,再用行掃描處理一遍就行了。這樣處理pixiArr也有利于進一步對算法進行優化。

上述方法雖然大概完成了摳圖效果,但是這種簡單處理還會有許多情況沒有考慮到。

比如右邊頭發這里是行掃描和列掃描都無法觸碰到的區域↓

 

下面的衣服也因為顏色和底色一樣且沒有邊界在列掃描中被直接抹去了↓

 

最后

對于主體和底色區分度很大的圖片來說,最開始的那種方法就已經夠用了。這篇中我采用的容差和邊界處理算法的優化空間還很大,但是它們是非常容易實現與理解的,這篇權當做一個引子,各位完全可以根據自己的能力繼續去實現邊界與容差算法。

總結

以上所述是小編給大家介紹的html5利用canvas實現顏色容差摳圖功能,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對武林網網站的支持!
如果你覺得本文對你有幫助,歡迎轉載,煩請注明出處,謝謝!

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 本色视频aaaaaa一级网站 | 日本欧美在线播放 | 国产99一区二区 | 中韩毛片| 精品一区二区久久久久久久网精 | 操操操操网 | 亚洲日本高清 | 久久精精品 | 99视频网址 | 久久国产一二三 | 欧美一级做 | 免费网址黄 | 午夜精品毛片 | 精品成人av一区二区三区 | 一本色道久久综合亚洲精品图片 | 黄色一级片毛片 | 99视频有精品视频高清 | 成人福利在线视频 | 伊人99re | 国产在线精品区 | 欧美一区中文字幕 | 欧美一区二区精品夜夜嗨 | 毛片韩国 | 欧美中文字幕一区二区 | 欧美性生活久久久 | 毛片在哪看 | 91成人免费在线观看 | 久久精品国产久精国产 | 激情宗合网 | 久草在线资源福利站 | 青热久思思 | 免费看成人毛片 | 久久久久久亚洲国产精品 | 国产一区二区三区四区五区精品 | 九九热在线视频观看 | 亚洲国产精品久久久久制服红楼梦 | 一级做a爱视频 | 调教小男生抽打尿孔嗯啊视频 | 在线高清中文字幕 | 亚洲第一黄色网 | 欧美成人精品一级 |