ユーザインタフェース背景色除去
58990 ワード
イントロ
私の個人的なプロジェクトのために、私はフロントエンド側のイメージバックグラウンド除去とJavaScriptを使用して色除去を実装する必要がありました.このポストでは、どのように私はそれを共有したいと思います.
以下のリンクで完全なデモを見ることができます.
https://swimmingkiim.github.io/color-background-remover/
インデックス.HTML設定
まず、インデックスを設定する必要があります.HTMLおよびインポートパッケージからUNPKG .
<body>
Color Remover
<button id="drawing-mode">remove</button>
<button id="remove-background">remove background</button>
<div id="color-box"></div>
<canvas id="canvas"></canvas>
<script src="https://unpkg.com/@tensorflow/[email protected]/dist/tf-core.js"></script>
<script src="https://unpkg.com/@tensorflow/[email protected]/dist/tf-converter.js"></script>
<script src="https://unpkg.com/@tensorflow/[email protected]/dist/tf-backend-webgl.js"></script>
<script src="https://unpkg.com/@tensorflow-models/[email protected]/dist/deeplab.js"></script>
<script src="script.js"></script>
</body>
1 . DeePLAB ( TFJS )で画像の背景を削除する
この部分、私は参照の最初のリンクから多くの助けを得ました.あまり変わりませんでした.それで、私はちょうど1つずつ説明します.
1 .変数
let model;
const segmentImageButton = document.getElementById("remove-background");
segmentImageButton.style.display = "none";
const canvas = document.getElementById("canvas");
const originalImageCanvas = document.createElement("canvas");
const maskCanvas = document.createElement("canvas");
const ctx = canvas.getContext('2d');
const originalCtx = originalImageCanvas.getContext('2d');
const maskCtx = maskCanvas.getContext('2d');
イメージの背景を削除するには、DeePLABからモデルが必要です.DeePlab画像をセグメントにモデルを提供しています.また、画面上に表示されないマスクのキャンバスを準備する必要がありますが、ヘルパーキャンバスの背景データを記録する.DeePLABからロード可能な使用モデル
async function loadModel(modelName) {
model = await deeplab.load({ "base": modelName, "quantizationBytes": 2 });
segmentImageButton.style.display = "inline-block";
}
DeePLABでは、イメージセグメンテーションのために3つの可能なモードがあります.この場合、' pascal 'モードを提案します.モデル名はすべて小文字で' pascal 'です.一度モデルを読み込むと、背景を削除することができます.モデルの前にバックグラウンドを削除しようとするユーザーがロードされた場合、エラーが発生します.予測(マスクを取得するセグメントイメージ)
async function predict() {
let prediction = await model.segment(image);
renderPrediction(prediction);
}
function renderPrediction(prediction) {
const { height, width, segmentationMap } = prediction;
const segmentationMapData = new ImageData(segmentationMap, width, height);
canvas.width = width;
canvas.height = height;
ctx.drawImage(image, 0, 0, width, height);
maskCanvas.width = width;
maskCanvas.height = height;
maskCtx.putImageData(segmentationMapData, 0, 0);
removeBackground([0,0,0], width, height);
}
今、あなたのイメージをセグメントすることができます.画像の型はhtmlimageです.セグメント関数は結果データを返します.そのデータでは、幅、高さ、およびsegmentationmapフィールドが必要です.幅と高さは分割画像のサイズです.segmentationmapは、セグメント化された像のイメージデータを参照する.これを使って描くならputImageData
キャンバス上のメソッドでは、異なるオブジェクトを表す色の組み合わせが表示されます.Pascalモードでは、背景は黒い色です.それで、あなたはマスクを作るためにこれを使うことができます.まず、MaskCanvas上でsegmenttationMapを描画します.セグメントデータを使用して背景を削除する
function removeBackground(color, width, height){
image.width = width;
image.height = height;
originalImage.width = width;
originalImage.height = height;
canvas.width =width;
canvas.height =height;
originalImageCanvas.width =width;
originalImageCanvas.height =height;
ctx.drawImage(image, 0,0,width,height);
var canvasData = ctx.getImageData(0, 0, width, height),
pix = canvasData.data;
var maskCanvasData = maskCtx.getImageData(0, 0, width, height),
maskPix = maskCanvasData.data;
for (var i = 0, n = maskPix.length; i <n; i += 4) {
if(maskPix[i] === color[0] && maskPix[i+1] === color[1] && maskPix[i+2] === color[2]){
maskPix[i+3] = 0;
pix[i+3] = 0;
}
}
ctx.putImageData(canvasData, 0, 0);
maskCtx.putImageData(maskCanvasData, 0, 0);
const base64 = canvas.toDataURL();
image.src = base64
originalImage.src = originalImage.src;
}
この部分では、参照の2番目のリンクから助けを得ました.最初に、表示されたキャンバス上の現在の画像を描画、他のキャンバスに元の画像.画像のサイズがセグメンテーション後に変更されるので、更新するには、あなたのオリジナル(バックアップ用)のイメージを再描画する必要があります.
第二に、キャンバスとマスクのキャンバスから画像データを取得します.をループします.あなたがマスク・キャンバスの上に黒いピクセルを見つけるならば、それを透明にしてください.ピクセルデータ配列は、各ピクセルのRGBA番号の配列ですので、一度に4をジャンプする必要があります.
第三に、キャンバスとマスクキャンバス上の更新画像を再描画します.キャンバスからデータURLを取得し、現在のイメージのsrcを更新します.
2 .マウスの位置に応じて色部分を選択する
さて、インタラクティブな色除去を実装する必要があります.
1 .変数とイメージの設定
const canvas = document.getElementById("canvas");
const originalImageCanvas = document.createElement("canvas");
const modeButton = document.getElementById("drawing-mode");
const ctx = canvas.getContext('2d');
const originalCtx = originalImageCanvas.getContext('2d');
const colorBox = document.getElementById("color-box");
let mode = "remove";
colorBox.style.width = "20px";
colorBox.style.height = "20px";
colorBox.style.backgroundColor = "black";
const selectColorData = [19, 163, 188];
const removeColorData = [255,255,255, 0];
let originalImage;
let image;
let imageSize = {
width: 500,
height: 500,
}
const brushSize = 20;
let circle = new Path2D();
circle.stroke = `rgb(${selectColorData.join(",")})`;
const imageSrc = "https://images.unsplash.com/photo-1648199840917-9e4749a5047e?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=687&q=80";
const canvasOffset = {
x: canvas.getBoundingClientRect().left,
y: canvas.getBoundingClientRect().top,
}
const setCanvas = () => {
const _image = new Image();
_image.onload = () => {
image = _image.cloneNode();
image.onload = null;
originalImage = _image.cloneNode();
imageSize = {
width: Math.min(_image.width, imageSize.width),
height: Math.min(_image.width, imageSize.width) * (_image.height /_image.width)
}
canvas.width = imageSize.width;
canvas.height = imageSize.height;
originalImageCanvas.width = imageSize.width;
originalImageCanvas.height = imageSize.height;
image.width = imageSize.width;
image.height = imageSize.height;
_image.width = imageSize.width;
_image.height = imageSize.height;
originalImage = _image.cloneNode();
ctx.drawImage(image, 0,0, image.width, image.height);
originalCtx.drawImage(_image, 0,0, _image.width, _image.height);
console.log(originalImageCanvas)
}
_image.crossOrigin = "anonymous";
_image.src = imageSrc;
}
あなたのイメージがロードされるとき、される若干の作品があります.キャンバスと元のキャンバスを初期化する必要があります(この後は変更されません.イメージを回復するためのリファレンスです)、SRC(HTMLイメージ要素).最後に、キャンバスとオリジナルのキャンバスに画像を描画します.HTMLキャンバスから特定の色を削除する
const isInColorRange = (targetColor, compareTo, i) => {
return (
targetColor[i] >= compareTo[0] - 10
&& targetColor[i] <= compareTo[0] + 10
&& targetColor[i+1] >= compareTo[1] - 10
&& targetColor[i+1] <= compareTo[1] + 10
&& targetColor[i+2] >= compareTo[2] - 10
&& targetColor[i+2] <= compareTo[2] + 10
)
}
const selectColor = (colorData) => {
let canvasData = ctx.getImageData(0, 0, canvas.width, canvas.height),
pix = canvasData.data;
for (let i = 0, n = pix.length; i <n; i += 4) {
if(isInColorRange(pix, colorData, i)){
pix[i] = selectColorData[0];
pix[i+1] = selectColorData[1];
pix[i+2] = selectColorData[2];
}
}
ctx.putImageData(canvasData, 0, 0);
}
const removeColor = (colorData) => {
let canvasData = ctx.getImageData(0, 0, canvas.width, canvas.height),
pix = canvasData.data;
for (let i = 0, n = pix.length; i <n; i += 4) {
if(isInColorRange(pix, colorData, i)){
pix[i] = removeColorData[0];
pix[i+1] = removeColorData[1];
pix[i+2] = removeColorData[2];
pix[i+3] = removeColorData[3];
}
}
ctx.putImageData(canvasData, 0, 0);
}
それはtfjs(Deeplab)で背景を削除するようです.ピクセルデータとループを取得し、それらを変更して下さい.iSinColorRangeは、他の番号に10を変更することができますし、プロジェクトを調整するカスタマイズ可能です.4 .元のイメージをHTMLキャンバスに戻す
const healArea = (position) => {
ctx.clearRect(0,0, image.width, image.height);
ctx.drawImage(originalImage, 0,0, originalImage.width, originalImage.height);
ctx.globalCompositeOperation = "destination-in";
ctx.moveTo(position.x, position.y);
circle.moveTo(position.x, position.y);
circle.arc(position.x, position.y, brushSize/2, 0, 2 * Math.PI);
ctx.fill(circle);
ctx.globalCompositeOperation = "source-over";
ctx.drawImage(image, 0,0, image.width, image.height);
}
const removeArea = (position) => {
ctx.clearRect(0,0, image.width, image.height);
ctx.drawImage(image, 0,0, image.width, image.height);
ctx.globalCompositeOperation = "destination-out";
ctx.moveTo(position.x, position.y);
circle.moveTo(position.x, position.y);
circle.arc(position.x, position.y, brushSize/2, 0, 2 * Math.PI);
ctx.fill(circle);
ctx.globalCompositeOperation = "source-over";
}
また、上記の2つのfuctionのロジックも非常にシミュレートされます.違いは、異なるGlobalCSyntax操作を使用しているということです.領域を削除することは、それ自身の領域を取り除くために「目的地外」を使用しています、そして、ヒーリング地域は円自体の領域だけを引くために「目的地」を使っていて、他を取り除きます.レジスタマウスイベント
最後に、マウスの移動、donwおよびupイベントで適切にすべてのそれらの機能を結合する.私は詳細には行かない.私は、以下のコードがどんな特別な新しい承認も含むと思いません.
ユーティリティ
const detectColor = (position) => {
const colorData = ctx.getImageData(
position.x,
position.y,
1,
1
).data;
return colorData;
}
const changeColorBoxColor = (colorData) => {
const rgba = `rgba(${colorData.join(",")})`;
colorBox.style.backgroundColor = rgba;
}
onmousemove (マウスダウンなし)
const onMouseMoveSelectColor = (e) => {
ctx.drawImage(image, 0,0, image.width, image.height);
const position = {
x: e.clientX - canvasOffset.x,
y: e.clientY - canvasOffset.y,
}
const color = detectColor(position);
changeColorBoxColor(color);
if (mode === "remove by color") {
selectColor(
color,
position.x,
position.y
);
} else {
selectArea(
position.x,
position.y
);
}
}
onmousemove (マウスダウンで)
const onMouseDownAndMoveRemoveColor = (e) => {
const callback = (e) => {
const position = {
x: e.clientX - canvasOffset.x,
y: e.clientY - canvasOffset.y,
}
const color = detectColor(position);
if (mode === "remove by color") {
removeColor(
color,
position.x,
position.y
)
} else if (mode === "heal area") {
healColor(
position,
);
} else {
removeArea(position);
}
}
canvas.onmousemove = callback;
callback(e);
}
4 .登録リスナー
const toggleMode = (e) => {
if (e.target.innerText === "remove by color") {
mode = "heal area";
} else if (e.target.innerText === "heal area") {
mode = "remove area";
} else {
mode = "remove by color";
}
e.target.innerText = mode;
}
const registerListener = () => {
canvas.onmousemove = onMouseMoveSelectColor;
canvas.onmousedown = onMouseDownAndMoveRemoveColor;
canvas.onmouseup = (e) => {
canvas.onmousemove = null;
canvas.onmousemove = onMouseMoveSelectColor;
image.src = canvas.toDataURL();
};
canvas.onmouseleave = (e) => {
canvas.onmousemove = null;
canvas.onmousemove = onMouseMoveSelectColor;
ctx.drawImage(image, 0,0, image.width, image.height);
}
modeButton.onclick = toggleMode;
}
結論
私はイメージエディタプロジェクトでこれらを実装する予定です.私のプロジェクトの実装を見て興味があれば、下記のリンクをチェックアウトしてください.
https://online-image-maker.com/
乾杯!
参考文献
Reference
この問題について(ユーザインタフェース背景色除去), 我々は、より多くの情報をここで見つけました https://dev.to/swimmingkiim/user-interactive-background-color-remover-using-html-canvas-2p0kテキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol