LoginSignup
0
0

More than 3 years have passed since last update.

【入門者向け】Canvas入門講座#14 2値化してみよう【JavaScript】

Last updated at Posted at 2020-12-01

問題14

問題13~15は問題9がベースとなっています。まず問題9を実装してください。

画像読み込み後、binarize押下時に2値化処理をせよ。
2値化処理はグレースケール後、127より大きい場合は255,それ以外の場合は0となるように処理すること。

グレースケールとは以下の式で表せる。
Gray = 0.299 * Red + 0.587 * Green + 0.114 * Blue;

以下のHTMLを使用すること。

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>問題14</title>
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<script>
$(() => {

    $('#my-file').on('change', e => {
        const img = new Image();
        $(img).on('load', e => {            
        });
        img.src = URL.createObjectURL(e.target.files[0]);
    });

    $('#binarize-button').click(e => {        
    });

});
</script>
</head>
<body>
<canvas id="my-canvas" width="500" height="300"></canvas>
<br>
<input id="my-file" type="file" />
<br>
<input id="binarize-button" type="button" value="binarize" />
</body>
</html>

解答

問題9の分の回答も併せて貼っておきます。

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>問題14</title>
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<script>
$(() => {

    $('#my-file').on('change', e => {
        const img = new Image();
        $(img).on('load', e => {
            // コンテキストを取得
            const ctx = $('#my-canvas')[0].getContext('2d');

            // canvasを黒色で塗りつぶす
            ctx.fillStyle = '#000000';
            ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);            

            // canvasと画像のアスペクト比を求める
            const canvasWidth = $('#my-canvas').prop('width'),
                canvasHeight = $('#my-canvas').prop('height');
                canvasAspect = canvasWidth / canvasHeight;  // canvasのアスペクト比
                imgAspect = img.width / img.height; // imgのアスペクト比

            // canvasと画像のアスペクト比を比較し、貼り付ける領域を決定する
            let dstWidth, dstHeight;
            if(canvasAspect > imgAspect) {// canvasの方が横長
                dstHeight = canvasHeight;
                dstWidth = dstHeight * imgAspect;               
            } else {// canvasの方が縦長
                dstWidth = canvasWidth;
                dstHeight = dstWidth / imgAspect;
            }

            // 画像を貼り付ける
            ctx.drawImage(img, 0, 0, img.width, img.height, 0, 0, dstWidth, dstHeight);
        });
        img.src = URL.createObjectURL(e.target.files[0]);
    });

    $('#binarize-button').click(e => {
        const canvas = $('#my-canvas')[0],
            ctx = canvas.getContext('2d');

        ctx.save();

        const imgData = ctx.getImageData(0, 0, canvas.width, canvas.height),
            data = imgData.data;

        for(let p = 0; p < data.length; p += 4) {
            // rgbを求める
            const red = data[p],
                green = data[p + 1],
                blue = data[p + 2];

            // グレースケールの値を求める
            let gray = 0.299 * red + 0.587 * green + 0.114 * blue;
            // 2値化する
            if(gray > 127) {
                gray = 255;
            } else {
                gray = 0;
            }

            // グレースケール化する(グレーで塗りつぶす)
            for (let i = 0; i < 3; i += 1) {
                data[p + i] = gray;
            }
        }

        // imageDataをcanvasに貼り付ける
        ctx.putImageData(imgData, 0, 0);

        ctx.restore();
    });

});
</script>
</head>
<body>
<canvas id="my-canvas" width="500" height="300"></canvas>
<br>
<input id="my-file" type="file" />
<br>
<input id="binarize-button" type="button" value="binarize" />
</body>
</html>

2値化できました!
image.png

解説

問題13と酷似しているのでポイントだけ説明します。
グレースケール化するときの値を計算して、閾値(今回は127)より大きい場合は255,それ以外は0にします。

// グレースケールの値を求める
let gray = 0.299 * red + 0.587 * green + 0.114 * blue;
// 2値化する
if(gray > 127) {
    gray = 255;
} else {
    gray = 0;
}

発展

2値化の閾値は手動で決める場合と、計算して求める場合があります。
計算で2値化の閾値を求める方法として「大津の2値化」というロジックが有名です。
興味のある方は調べてみてください。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0