簡體   English   中英

使圖像變白和透明的算法

[英]Algorithm to make image white and transparent

這種影響(如下圖所示)是通過幾個簡單的Photoshop步驟完成的,顏色部分變為白色,背景(各種陰影為白色,灰色)變透明了。 用畫布可以實現嗎?

以下圓圈內的圖像是最終結果。

圖像最初是彩色的,就像頂部圖像中的第二個是這樣的:

看到中間的那個圓圈,基本上所有白色都以鋸齒的方式被切掉了。

與此zoho徽標相同:

倒數第二個最初是這樣的:

除了紅色R在中間只是Y,而不是在圖像中看到的所有文本和綠色條帶之外,它周圍只有灰色陰影,帶有一些粒狀紋理。 然后通過photoshop將Y變成透明的,將紋理和印記制作成實心的,除去3d陰影等。

通過photoshop算法將其放置在yandex戳上方,即可達到此目的(我將白色替換為黑色,以進行演示/可見性的偽裝)

在Photoshop算法之后,這是鋸齒狀的,但是在最終應用中,圖像被縮小到80x80px左右,這使它看起來真正平滑且抗鋸齒。 因此,真正的最終結果是看起來非常不錯。

問題是多方面的,因為某些區域需要使用不同的方法,例如,最后一張圖像需要將主文本轉換為白色,但要保持透明,而同一圖像的底部欄是實心的,但需要將白色文本保留而要刪除的純色背景。

通過實施工具來選擇區域並手動應用各種運算符是可行的-自動處理將比看起來要面臨的挑戰大得多。

您可以要求用戶僅上傳帶有Alpha通道的圖像。 為此,您可以簡單地將每個非透明像素替換為白色。 在我看來,它不僅僅是技術問題,而是政策問題。

例如

取徽標:

商標

 var img = new Image(); img.crossOrigin = ""; img.onload = process; img.src = "http://i.imgur.com/HIhnb4A.png"; // load the logo function process() { var canvas = document.querySelector("canvas"), // canvas ctx = canvas.getContext("2d"), // context w = this.width, // image width/height h = this.height, idata, data32, len, i, px; // iterator, pixel etc. canvas.width = w; // set canvas size canvas.height = h; ctx.drawImage(this, 0, 0); // draw in image idata = ctx.getImageData(0, 0, w, h); // get imagedata data32 = new Uint32Array(idata.data.buffer); // use uint32 view for speed len = data32.length; for(i = 0; i < len; i++) { // extract alpha channel from a pixel px = data32[i] & 0xff000000; // little-endian: ABGR // any non-transparency? ie. alpha > 0 if (px) { data32[i] = px | 0xffffff; // set this pixel to white, keep alpha level } } // done ctx.putImageData(idata, 0, 0); } 
 body {background:gold} 
 <canvas></canvas> 

現在問題很容易發現:“ @”字符很穩定,因為它后面沒有透明性。 要使其自動化,首先需要剔除所有白色,然后應用上面演示的過程。 但是,這可能在這種情況下可行,但對大多數人來說可能不是一件好事。

還存在抗鋸齒問題,因為我們不分析白色像素周圍的邊緣,因此無法知道要剔除多少白色。 另一個可能的挑戰是經過ICC校正的圖像,根據所使用的ICC配置文件,瀏覽器支持等,白色可能不是白色。

但是,從某種程度上講,它是可行的-采取上述代碼,並以預先步驟剔除此徽標的全白像素:

 var img = new Image(); img.crossOrigin = ""; img.onload = process; img.src = "http://i.imgur.com/HIhnb4A.png"; // load the logo function process() { var canvas = document.querySelector("canvas"), // canvas ctx = canvas.getContext("2d"), // context w = this.width, h = this.height, idata, data32, len, i, px; // iterator, pixel etc. canvas.width = w; // set canvas size canvas.height = h; ctx.drawImage(this, 0, 0); // draw in image idata = ctx.getImageData(0, 0, w, h); // get imagedata data32 = new Uint32Array(idata.data.buffer); // use uint32 view for speed len = data32.length; for(i = 0; i < len; i++) { px = data32[i]; // pixel // is white? then knock it out if (px === 0xffffffff) data32[i] = px = 0; // extract alpha channel from a pixel px = px & 0xff000000; // little-endian: ABGR // any non-transparency? ie. alpha > 0 if (px) { data32[i] = px | 0xffffff; // set this pixel to white, keep alpha level } } ctx.putImageData(idata, 0, 0); } 
 body {background:gold} 
 <canvas></canvas> 

用這個

private draw(base64: string) {
  // example size
  const width = 200;
  const height = 70;
  const image = new Image();
  image.onload = () => {
    const canvas = document.createElement("canvas");
    canvas.width = width;
    canvas.height = height;
    const ctx = canvas.getContext("2d");
    ctx.drawImage(image, 0, 0);
    const imageData = ctx.getImageData(0, 0, width, height);
    for (let x = 0; x < imageData.width; x++) {
      for (let y = 0; y < imageData.height; y++) {
        const offset = (y * imageData.width + x) * 4;
        const r = imageData.data[offset];
        const g = imageData.data[offset + 1];
        const b = imageData.data[offset + 2];
        // if it is pure white, change its alpha to 0
        if (r == 255 && g == 255 && b == 255) {
          imageData.data[offset + 3] = 0;
        }
      }
    }
    ctx.putImageData(imageData, 0, 0);
    // output base64
    const result = canvas.toDataURL();
  };
  image.src = base64;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM