ハーフトーニングをUnityでやってみよう

# ハーフトーニングとは？

みなさんはプリンターを使ったことはありますか？あのコピーとか印刷とかをやってくれるあれです。もちろん使ったことありますよね？

最近のプリンターは家庭用でもカラープリントができるようになりましたよね。

しかし、原始的なプリンターにはカラープリント機能は無く、印刷対象に対して「インクを出す」という行為と「インクを出さない」という2つの機能しかありませんでした。

ここで、あることが問題になります。それは「白黒の濃淡をどう表現するか」という問題です。

原始的なプリンタはインクを出すか出さないかの2つの行動しかとれず、少しだけインクを出すなんてこともできません。

この問題を解決する手法がハーフトーニングです。ずばり、白インクと黒インクの打ち方を工夫することで、あたかも濃淡がついているように見せる技術といったところでしょうか。

#有名なハーフトーニング

有名なハーフトーニングの中でも今回は以下の３つについてお話します。

1. 濃度パターン法
1. ディザ法
1. 誤差拡散法

# 濃度パターン法

![資料画像その１.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1522500/0d458647-9e78-3f04-e41b-1e130a56365d.png)

![123456789.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1522500/1755177a-f932-f222-7e0c-9d978ffa5636.png)


![987654321.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1522500/89e83aca-a8b6-3a90-82eb-ad5aaf3d9073.png)




元画像の4 * 4画素を17諧調に分類し、諧調に対応する 4 * 4 画素のパターンで置き換え、2値画像（モノクロ画像）で表す方式。

・メリット
17諧調で表現できる

・デメリット
画像が荒くなる

# ディザ法

![資料画像その3 (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1522500/8306f9d6-01ab-e88b-0e95-b868d4026d54.png)

![資料画像その6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1522500/f5ad2cf6-a879-a6d9-fc0a-b97b1ee63eb9.png)



元画像を4 * 4の領域で処理し、画素ごとに異なる基準値を用いる方式。

・メリット
解像度（画像サイズ）を維持できる

・デメリット
繰り返しパターンが目立つ

#誤差拡散法

![資料画像その４.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1522500/5dc3410c-6553-704f-f858-2416f2c7420e.png)

![資料画像その7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1522500/351a4839-4e03-66d1-1a49-17204bbbf9ba.png)



ある画素の基準値からの誤差を周辺の画素に伝播させ、誤差を軽減する方式。

・メリット
誤差を周りの画素に伝播させるため比較的正しく表現できる
解像度（画像サイズ）を維持できる

・デメリット
画像のざらざら感が増える（語彙力）

# Unityで実装する

さっそく実装していきましょう！

おおまかな処理は、

1. スクリプトがアタッチされているオブジェクトのSpriteのTextureを取得する
1. 取得したTextureのピクセル情報を配列Aに格納する
1. ピクセルのグレイスケール化とピクセルの諧調に対するパターンを新しい配列Bに格納する
1. Textureを配列Bで更新する
1. Textureをpng形式で画像を保存する

です。頑張ってコードを書いていきましょう。

## 濃度パターン法

はいそして出来上がったものがこちらになります。コードが非常に長いので折りたためるようにしてあります。

※実行するときにかなり重くなりますので注意！

<details>
<summary>濃度パターン法（DensityPattern_Logic）のコード</summary>
<div>

```C#:DensityPattern_Logic.C#

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;
using UnityEditor;
using System;

public class DensityPattern_Re_Logic : MonoBehaviour
{
    public Texture2D drawTexture;

    public int[] DensityPattern;
    public Color32[] DensityPatternBuffer;

    void Start()
    {
        Texture2D mainTexture = GetComponent<SpriteRenderer>().sprite.texture;
        Color32[] pixels = mainTexture.GetPixels32();

        DensityPattern = new int[pixels.Length];
        DensityPatternBuffer = new Color32[(mainTexture.width) * (mainTexture.height)];

        drawTexture = new Texture2D(mainTexture.width, mainTexture.height, TextureFormat.RGBA32, false);
        drawTexture.filterMode = FilterMode.Point;


        for (int i = 0; i < mainTexture.height; i++)
        {
            for (int j = 0; j < mainTexture.width; j++)
            {
                /////↓グレイスケール化の処理

                int k = j + i * mainTexture.width;

                byte gray = (byte)(pixels[k].r * 0.2126 + pixels[k].g * 0.7152 + pixels[k].b * 0.0722);

                pixels[k] = new Color32((byte)(gray), (byte)(gray), (byte)(gray), pixels[k].a);

                /////↑グレイスケール化の処理
            }
        }

        for (int i = 0; i < mainTexture.height - 4; i++)
        {
            for (int j = 0; j < mainTexture.width - 4; j++)
            {
                if (i % 4 == 0 && j % 4 == 0)
                {
                    float Adv = 0;

                    for (int k = 0; k < 4; k++)
                    {
                        for (int l = 0; l < 4; l++)
                        {
                            Adv += pixels[(j + l) + (i + k) * mainTexture.width].r;
                        }
                    }

                    float gray = Adv / 16;

                    Debug.Log(" i = " + i + " | j = " + j + " | gray = " + gray);

                    if (0 <= gray && gray < 8)
                    {
                        DensityPatternBuffer[(j + 0) + (i + 0) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 1) + (i + 0) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 2) + (i + 0) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 3) + (i + 0) * (mainTexture.width)] = Color.black;

                        DensityPatternBuffer[(j + 0) + (i + 1) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 1) + (i + 1) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 2) + (i + 1) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 3) + (i + 1) * (mainTexture.width)] = Color.black;

                        DensityPatternBuffer[(j + 0) + (i + 2) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 1) + (i + 2) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 2) + (i + 2) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 3) + (i + 2) * (mainTexture.width)] = Color.black;

                        DensityPatternBuffer[(j + 0) + (i + 3) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 1) + (i + 3) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 2) + (i + 3) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 3) + (i + 3) * (mainTexture.width)] = Color.black;

                    }
                    else if (8 <= gray && gray < 16)
                    {
                        DensityPatternBuffer[(j + 0) + (i + 0) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 1) + (i + 0) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 2) + (i + 0) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 3) + (i + 0) * (mainTexture.width)] = Color.black;

                        DensityPatternBuffer[(j + 0) + (i + 1) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 1) + (i + 1) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 2) + (i + 1) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 3) + (i + 1) * (mainTexture.width)] = Color.black;

                        DensityPatternBuffer[(j + 0) + (i + 2) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 1) + (i + 2) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 2) + (i + 2) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 3) + (i + 2) * (mainTexture.width)] = Color.black;

                        DensityPatternBuffer[(j + 0) + (i + 3) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 1) + (i + 3) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 2) + (i + 3) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 3) + (i + 3) * (mainTexture.width)] = Color.black;
                    }
                    else if (16 <= gray && gray < 32)
                    {
                        DensityPatternBuffer[(j + 0) + (i + 0) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 1) + (i + 0) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 2) + (i + 0) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 3) + (i + 0) * (mainTexture.width)] = Color.black;

                        DensityPatternBuffer[(j + 0) + (i + 1) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 1) + (i + 1) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 2) + (i + 1) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 3) + (i + 1) * (mainTexture.width)] = Color.black;

                        DensityPatternBuffer[(j + 0) + (i + 2) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 1) + (i + 2) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 2) + (i + 2) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 3) + (i + 2) * (mainTexture.width)] = Color.black;

                        DensityPatternBuffer[(j + 0) + (i + 3) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 1) + (i + 3) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 2) + (i + 3) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 3) + (i + 3) * (mainTexture.width)] = Color.black;
                    }
                    else if (32 <= gray && gray < 48)
                    {
                        DensityPatternBuffer[(j + 0) + (i + 0) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 1) + (i + 0) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 2) + (i + 0) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 3) + (i + 0) * (mainTexture.width)] = Color.black;

                        DensityPatternBuffer[(j + 0) + (i + 1) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 1) + (i + 1) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 2) + (i + 1) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 3) + (i + 1) * (mainTexture.width)] = Color.black;

                        DensityPatternBuffer[(j + 0) + (i + 2) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 1) + (i + 2) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 2) + (i + 2) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 3) + (i + 2) * (mainTexture.width)] = Color.black;

                        DensityPatternBuffer[(j + 0) + (i + 3) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 1) + (i + 3) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 2) + (i + 3) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 3) + (i + 3) * (mainTexture.width)] = Color.black;
                    }
                    else if (48 <= gray && gray < 64)
                    {
                        DensityPatternBuffer[(j + 0) + (i + 0) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 1) + (i + 0) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 2) + (i + 0) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 3) + (i + 0) * (mainTexture.width)] = Color.black;

                        DensityPatternBuffer[(j + 0) + (i + 1) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 1) + (i + 1) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 2) + (i + 1) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 3) + (i + 1) * (mainTexture.width)] = Color.black;

                        DensityPatternBuffer[(j + 0) + (i + 2) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 1) + (i + 2) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 2) + (i + 2) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 3) + (i + 2) * (mainTexture.width)] = Color.black;

                        DensityPatternBuffer[(j + 0) + (i + 3) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 1) + (i + 3) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 2) + (i + 3) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 3) + (i + 3) * (mainTexture.width)] = Color.black;
                    }
                    else if (64 <= gray && gray < 80)
                    {
                        DensityPatternBuffer[(j + 0) + (i + 0) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 1) + (i + 0) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 2) + (i + 0) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 3) + (i + 0) * (mainTexture.width)] = Color.black;

                        DensityPatternBuffer[(j + 0) + (i + 1) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 1) + (i + 1) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 2) + (i + 1) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 3) + (i + 1) * (mainTexture.width)] = Color.black;

                        DensityPatternBuffer[(j + 0) + (i + 2) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 1) + (i + 2) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 2) + (i + 2) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 3) + (i + 2) * (mainTexture.width)] = Color.black;

                        DensityPatternBuffer[(j + 0) + (i + 3) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 1) + (i + 3) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 2) + (i + 3) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 3) + (i + 3) * (mainTexture.width)] = Color.white;
                    }
                    else if (80 <= gray && gray < 96)
                    {
                        DensityPatternBuffer[(j + 0) + (i + 0) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 1) + (i + 0) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 2) + (i + 0) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 3) + (i + 0) * (mainTexture.width)] = Color.black;

                        DensityPatternBuffer[(j + 0) + (i + 1) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 1) + (i + 1) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 2) + (i + 1) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 3) + (i + 1) * (mainTexture.width)] = Color.white;

                        DensityPatternBuffer[(j + 0) + (i + 2) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 1) + (i + 2) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 2) + (i + 2) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 3) + (i + 2) * (mainTexture.width)] = Color.black;

                        DensityPatternBuffer[(j + 0) + (i + 3) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 1) + (i + 3) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 2) + (i + 3) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 3) + (i + 3) * (mainTexture.width)] = Color.white;
                    }
                    else if (96 <= gray && gray < 112)
                    {
                        DensityPatternBuffer[(j + 0) + (i + 0) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 1) + (i + 0) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 2) + (i + 0) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 3) + (i + 0) * (mainTexture.width)] = Color.black;

                        DensityPatternBuffer[(j + 0) + (i + 1) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 1) + (i + 1) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 2) + (i + 1) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 3) + (i + 1) * (mainTexture.width)] = Color.white;

                        DensityPatternBuffer[(j + 0) + (i + 2) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 1) + (i + 2) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 2) + (i + 2) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 3) + (i + 2) * (mainTexture.width)] = Color.black;

                        DensityPatternBuffer[(j + 0) + (i + 3) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 1) + (i + 3) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 2) + (i + 3) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 3) + (i + 3) * (mainTexture.width)] = Color.white;
                    }
                    else if (112 <= gray && gray < 128)
                    {
                        DensityPatternBuffer[(j + 0) + (i + 0) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 1) + (i + 0) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 2) + (i + 0) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 3) + (i + 0) * (mainTexture.width)] = Color.black;

                        DensityPatternBuffer[(j + 0) + (i + 1) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 1) + (i + 1) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 2) + (i + 1) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 3) + (i + 1) * (mainTexture.width)] = Color.white;

                        DensityPatternBuffer[(j + 0) + (i + 2) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 1) + (i + 2) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 2) + (i + 2) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 3) + (i + 2) * (mainTexture.width)] = Color.black;

                        DensityPatternBuffer[(j + 0) + (i + 3) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 1) + (i + 3) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 2) + (i + 3) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 3) + (i + 3) * (mainTexture.width)] = Color.white;
                    }
                    else if (128 <= gray && gray < 144)
                    {
                        DensityPatternBuffer[(j + 0) + (i + 0) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 1) + (i + 0) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 2) + (i + 0) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 3) + (i + 0) * (mainTexture.width)] = Color.black;

                        DensityPatternBuffer[(j + 0) + (i + 1) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 1) + (i + 1) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 2) + (i + 1) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 3) + (i + 1) * (mainTexture.width)] = Color.white;

                        DensityPatternBuffer[(j + 0) + (i + 2) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 1) + (i + 2) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 2) + (i + 2) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 3) + (i + 2) * (mainTexture.width)] = Color.white;

                        DensityPatternBuffer[(j + 0) + (i + 3) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 1) + (i + 3) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 2) + (i + 3) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 3) + (i + 3) * (mainTexture.width)] = Color.white;
                    }
                    else if (144 <= gray && gray < 160)
                    {
                        DensityPatternBuffer[(j + 0) + (i + 0) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 1) + (i + 0) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 2) + (i + 0) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 3) + (i + 0) * (mainTexture.width)] = Color.white;

                        DensityPatternBuffer[(j + 0) + (i + 1) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 1) + (i + 1) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 2) + (i + 1) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 3) + (i + 1) * (mainTexture.width)] = Color.white;

                        DensityPatternBuffer[(j + 0) + (i + 2) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 1) + (i + 2) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 2) + (i + 2) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 3) + (i + 2) * (mainTexture.width)] = Color.white;

                        DensityPatternBuffer[(j + 0) + (i + 3) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 1) + (i + 3) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 2) + (i + 3) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 3) + (i + 3) * (mainTexture.width)] = Color.white;
                    }
                    else if (160 <= gray && gray < 176)
                    {
                        DensityPatternBuffer[(j + 0) + (i + 0) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 1) + (i + 0) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 2) + (i + 0) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 3) + (i + 0) * (mainTexture.width)] = Color.white;

                        DensityPatternBuffer[(j + 0) + (i + 1) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 1) + (i + 1) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 2) + (i + 1) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 3) + (i + 1) * (mainTexture.width)] = Color.white;

                        DensityPatternBuffer[(j + 0) + (i + 2) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 1) + (i + 2) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 2) + (i + 2) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 3) + (i + 2) * (mainTexture.width)] = Color.white;

                        DensityPatternBuffer[(j + 0) + (i + 3) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 1) + (i + 3) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 2) + (i + 3) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 3) + (i + 3) * (mainTexture.width)] = Color.white;
                    }
                    else if (176 <= gray && gray < 192)
                    {
                        DensityPatternBuffer[(j + 0) + (i + 0) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 1) + (i + 0) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 2) + (i + 0) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 3) + (i + 0) * (mainTexture.width)] = Color.white;

                        DensityPatternBuffer[(j + 0) + (i + 1) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 1) + (i + 1) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 2) + (i + 1) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 3) + (i + 1) * (mainTexture.width)] = Color.white;

                        DensityPatternBuffer[(j + 0) + (i + 2) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 1) + (i + 2) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 2) + (i + 2) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 3) + (i + 2) * (mainTexture.width)] = Color.white;

                        DensityPatternBuffer[(j + 0) + (i + 3) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 1) + (i + 3) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 2) + (i + 3) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 3) + (i + 3) * (mainTexture.width)] = Color.white;
                    }
                    else if (192 <= gray && gray < 208)
                    {
                        DensityPatternBuffer[(j + 0) + (i + 0) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 1) + (i + 0) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 2) + (i + 0) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 3) + (i + 0) * (mainTexture.width)] = Color.white;

                        DensityPatternBuffer[(j + 0) + (i + 1) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 1) + (i + 1) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 2) + (i + 1) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 3) + (i + 1) * (mainTexture.width)] = Color.white;

                        DensityPatternBuffer[(j + 0) + (i + 2) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 1) + (i + 2) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 2) + (i + 2) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 3) + (i + 2) * (mainTexture.width)] = Color.white;

                        DensityPatternBuffer[(j + 0) + (i + 3) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 1) + (i + 3) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 2) + (i + 3) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 3) + (i + 3) * (mainTexture.width)] = Color.white;
                    }
                    else if (208 <= gray && gray < 224)
                    {
                        DensityPatternBuffer[(j + 0) + (i + 0) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 1) + (i + 0) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 2) + (i + 0) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 3) + (i + 0) * (mainTexture.width)] = Color.white;

                        DensityPatternBuffer[(j + 0) + (i + 1) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 1) + (i + 1) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 2) + (i + 1) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 3) + (i + 1) * (mainTexture.width)] = Color.white;

                        DensityPatternBuffer[(j + 0) + (i + 2) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 1) + (i + 2) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 2) + (i + 2) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 3) + (i + 2) * (mainTexture.width)] = Color.white;

                        DensityPatternBuffer[(j + 0) + (i + 3) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 1) + (i + 3) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 2) + (i + 3) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 3) + (i + 3) * (mainTexture.width)] = Color.white;
                    }
                    else if (224 <= gray && gray < 240)
                    {
                        DensityPatternBuffer[(j + 0) + (i + 0) * (mainTexture.width)] = Color.black;
                        DensityPatternBuffer[(j + 1) + (i + 0) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 2) + (i + 0) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 3) + (i + 0) * (mainTexture.width)] = Color.white;

                        DensityPatternBuffer[(j + 0) + (i + 1) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 1) + (i + 1) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 2) + (i + 1) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 3) + (i + 1) * (mainTexture.width)] = Color.white;

                        DensityPatternBuffer[(j + 0) + (i + 2) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 1) + (i + 2) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 2) + (i + 2) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 3) + (i + 2) * (mainTexture.width)] = Color.white;

                        DensityPatternBuffer[(j + 0) + (i + 3) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 1) + (i + 3) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 2) + (i + 3) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 3) + (i + 3) * (mainTexture.width)] = Color.white;
                    }
                    else if (240 <= gray && gray <= 255)
                    {
                        DensityPatternBuffer[(j + 0) + (i + 0) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 1) + (i + 0) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 2) + (i + 0) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 3) + (i + 0) * (mainTexture.width)] = Color.white;

                        DensityPatternBuffer[(j + 0) + (i + 1) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 1) + (i + 1) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 2) + (i + 1) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 3) + (i + 1) * (mainTexture.width)] = Color.white;

                        DensityPatternBuffer[(j + 0) + (i + 2) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 1) + (i + 2) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 2) + (i + 2) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 3) + (i + 2) * (mainTexture.width)] = Color.white;

                        DensityPatternBuffer[(j + 0) + (i + 3) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 1) + (i + 3) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 2) + (i + 3) * (mainTexture.width)] = Color.white;
                        DensityPatternBuffer[(j + 3) + (i + 3) * (mainTexture.width)] = Color.white;
                    }

                }
            }
        }

        drawTexture.SetPixels32(DensityPatternBuffer);
        drawTexture.Apply();

        this.GetComponent<SpriteRenderer>().sprite = Sprite.Create(drawTexture, new Rect(0, 0, drawTexture.width, drawTexture.height), Vector2.zero);

        // PNG 画像としてファイル保存
        string filename = DateTime.Now.Year.ToString() + DateTime.Now.Month.ToString() + DateTime.Now.Day.ToString() + DateTime.Now.Hour.ToString() + DateTime.Now.Minute.ToString() + DateTime.Now.Second.ToString() + "_DensityPattern.png";
        File.WriteAllBytes($"{Application.dataPath}/Images/DensityPattern/{filename}", drawTexture.EncodeToPNG());
    }
}
```

</div>
</details>

## ディザ法

コードが非常に長いので折りたためるようにしてあります。

<details>
<summary>ディザ法（Dither_Logic）のコード</summary>
<div>

```C#:Dither_Logic.C#
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;
using UnityEditor;
using System;

//ディザ法（dither method）
public class Dither_Logic : MonoBehaviour
{
    public Texture2D drawTexture;

    public Color32[] DitherBuffer;

    void Start()
    {
        Texture2D mainTexture = GetComponent<SpriteRenderer>().sprite.texture;
        Color32[] pixels = mainTexture.GetPixels32();

        DitherBuffer = new Color32[mainTexture.width * mainTexture.height];

        drawTexture = new Texture2D(mainTexture.width, mainTexture.height, TextureFormat.RGBA32, false);
        drawTexture.filterMode = FilterMode.Point;

        for (int i = 0; i < mainTexture.height; i++)
        {
            for (int j = 0; j < mainTexture.width; j++)
            {
                /////↓グレイスケール化の処理

                int k = j + i * mainTexture.width;

                byte gray = (byte)(pixels[k].r * 0.2126 + pixels[k].g * 0.7152 + pixels[k].b * 0.0722);

                pixels[k] = new Color32((byte)(gray), (byte)(gray), (byte)(gray), pixels[k].a);

                /////↑グレイスケール化の処理

                if (i % 4 == 0)
                {
                    if (j % 4 == 0)
                    {
                        if ((gray / 16) > 0)
                        {
                            DitherBuffer[k] = Color.white;
                        }
                        else
                        {
                            DitherBuffer[k] = Color.black;
                        }
                    }
                    else if (j % 4 == 1)
                    {
                        if ((gray / 16) > 8)
                        {
                            DitherBuffer[k] = Color.white;
                        }
                        else
                        {
                            DitherBuffer[k] = Color.black;
                        }
                    }
                    else if (j % 4 == 2)
                    {
                        if ((gray / 16) > 2)
                        {
                            DitherBuffer[k] = Color.white;
                        }
                        else
                        {
                            DitherBuffer[k] = Color.black;
                        }
                    }
                    else if (j % 4 == 3)
                    {
                        if ((gray / 16) > 10)
                        {
                            DitherBuffer[k] = Color.white;
                        }
                        else
                        {
                            DitherBuffer[k] = Color.black;
                        }
                    }
                }
                else if (i % 4 == 1)
                {
                    if (j % 4 == 0)
                    {
                        if ((gray / 16) > 12)
                        {
                            DitherBuffer[k] = Color.white;
                        }
                        else
                        {
                            DitherBuffer[k] = Color.black;
                        }
                    }
                    else if (j % 4 == 1)
                    {
                        if ((gray / 16) > 4)
                        {
                            DitherBuffer[k] = Color.white;
                        }
                        else
                        {
                            DitherBuffer[k] = Color.black;
                        }
                    }
                    else if (j % 4 == 2)
                    {
                        if ((gray / 16) > 14)
                        {
                            DitherBuffer[k] = Color.white;
                        }
                        else
                        {
                            DitherBuffer[k] = Color.black;
                        }
                    }
                    else if (j % 4 == 3)
                    {
                        if ((gray / 16) > 6)
                        {
                            DitherBuffer[k] = Color.white;
                        }
                        else
                        {
                            DitherBuffer[k] = Color.black;
                        }
                    }
                }
                else if (i % 4 == 2)
                {
                    if (j % 4 == 0)
                    {
                        if ((gray / 16) > 3)
                        {
                            DitherBuffer[k] = Color.white;
                        }
                        else
                        {
                            DitherBuffer[k] = Color.black;
                        }
                    }
                    else if (j % 4 == 1)
                    {
                        if ((gray / 16) > 11)
                        {
                            DitherBuffer[k] = Color.white;
                        }
                        else
                        {
                            DitherBuffer[k] = Color.black;
                        }
                    }
                    else if (j % 4 == 2)
                    {
                        if ((gray / 16) > 1)
                        {
                            DitherBuffer[k] = Color.white;
                        }
                        else
                        {
                            DitherBuffer[k] = Color.black;
                        }
                    }
                    else if (j % 4 == 3)
                    {
                        if ((gray / 16) > 9)
                        {
                            DitherBuffer[k] = Color.white;
                        }
                        else
                        {
                            DitherBuffer[k] = Color.black;
                        }
                    }
                }
                else if (i % 4 == 3)
                {
                    if (j % 4 == 0)
                    {
                        if ((gray / 16) > 15)
                        {
                            DitherBuffer[k] = Color.white;
                        }
                        else
                        {
                            DitherBuffer[k] = Color.black;
                        }
                    }
                    else if (j % 4 == 1)
                    {
                        if ((gray / 16) > 7)
                        {
                            DitherBuffer[k] = Color.white;
                        }
                        else
                        {
                            DitherBuffer[k] = Color.black;
                        }
                    }
                    else if (j % 4 == 2)
                    {
                        if ((gray / 16) > 13)
                        {
                            DitherBuffer[k] = Color.white;
                        }
                        else
                        {
                            DitherBuffer[k] = Color.black;
                        }
                    }
                    else if (j % 4 == 3)
                    {
                        if ((gray / 16) > 5)
                        {
                            DitherBuffer[k] = Color.white;
                        }
                        else
                        {
                            DitherBuffer[k] = Color.black;
                        }
                    }
                }

            }
        }

        drawTexture.SetPixels32(DitherBuffer);
        drawTexture.Apply();

        this.GetComponent<SpriteRenderer>().sprite = Sprite.Create(drawTexture, new Rect(0, 0, drawTexture.width, drawTexture.height), Vector2.zero);

        // PNG 画像としてファイル保存
        string filename = DateTime.Now.Year.ToString() + DateTime.Now.Month.ToString() + DateTime.Now.Day.ToString() + DateTime.Now.Hour.ToString() + DateTime.Now.Minute.ToString() + DateTime.Now.Second.ToString() + "_DitherPattern.png";
        File.WriteAllBytes($"{Application.dataPath}/Images/DitherPattern/{filename}", drawTexture.EncodeToPNG());
    }
}

```

</div>
</details>

## 誤差拡散法

コードが非常に長いので折りたためるようにしてあります。

<details>
<summary>誤差拡散法（ErrorDiffusion_Logic）のコード</summary>
<div>

```C#:ErrorDiffusion_Logic.C#
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;
using UnityEditor;
using System;

//誤差拡散法（error diffusion method）
public class ErrorDiffusion_Logic : MonoBehaviour
{
    public Texture2D drawTexture;

    public float[] ErrorBuffer;
    public Color32[] ErrorDiffusionPatternBuffer;

    void Start()
    {
        Texture2D mainTexture = GetComponent<SpriteRenderer>().sprite.texture;
        Color32[] pixels = mainTexture.GetPixels32();

        ErrorBuffer = new float[pixels.Length];
        ErrorDiffusionPatternBuffer = new Color32[mainTexture.width * mainTexture.height];

        drawTexture = new Texture2D(mainTexture.width, mainTexture.height, TextureFormat.RGBA32, false);
        drawTexture.filterMode = FilterMode.Point;

        for (int i = 0; i < mainTexture.height; i++)
        {
            for (int j = 0; j < mainTexture.width; j++)
            {
                /////↓グレイスケール化の処理

                int k = j + i * mainTexture.width;

                byte gray = (byte)(pixels[k].r * 0.2126 + pixels[k].g * 0.7152 + pixels[k].b * 0.0722);

                //buffer[k] = new Color32((byte)(gray), (byte)(gray), (byte)(gray), buffer[k].a);

                /////↑グレイスケール化の処理

                ErrorBuffer[k] = (float)gray;
            }
        }

        for (int i = 0; i < mainTexture.height; i++)
        {
            for (int j = 0; j < mainTexture.width; j++)
            {
                float error = 0;

                int k = j + i * mainTexture.width;

                if (ErrorBuffer[k] > 127)
                {
                    error = ErrorBuffer[k] - 255;

                    ErrorDiffusionPatternBuffer[k] = Color.white;
                }
                else if (ErrorBuffer[k] <= 127)
                {
                    error = ErrorBuffer[k] - 0;

                    ErrorDiffusionPatternBuffer[k] = Color.black;
                }

                if (j + 1 < mainTexture.width)
                {
                    ErrorBuffer[(j + 1) + i * mainTexture.width] = ErrorBuffer[(j + 1) + i * mainTexture.width] + ((5.0f / 16.0f) * error);
                }

                if (j < 0 && i + 1 < mainTexture.height)
                {
                    ErrorBuffer[(j - 1) + (i + 1) * mainTexture.width] = ErrorBuffer[(j - 1) + (i + 1) * mainTexture.width] + ((3.0f / 16.0f) * error);
                }

                if (i + 1 < mainTexture.height)
                {
                    ErrorBuffer[j + (i + 1) * mainTexture.width] = ErrorBuffer[j + (i + 1) * mainTexture.width] + ((5.0f / 16.0f) * error);
                }

                if (j + 1 < mainTexture.width && i + 1 < mainTexture.height)
                {
                    ErrorBuffer[(j + 1) + (i + 1) * mainTexture.width] = ErrorBuffer[(j + 1) + (i + 1) * mainTexture.width] + ((3.0f / 16.0f) * error);
                }
            }
        }

        drawTexture.SetPixels32(ErrorDiffusionPatternBuffer);
        drawTexture.Apply();

        this.GetComponent<SpriteRenderer>().sprite = Sprite.Create(drawTexture, new Rect(0, 0, drawTexture.width, drawTexture.height), Vector2.zero);

        // PNG 画像としてファイル保存
        string filename = DateTime.Now.Year.ToString() + DateTime.Now.Month.ToString() + DateTime.Now.Day.ToString() + DateTime.Now.Hour.ToString() + DateTime.Now.Minute.ToString() + DateTime.Now.Second.ToString() + "_ErrorDiffusion.png";
        File.WriteAllBytes($"{Application.dataPath}/Images/ErrorDiffusionPattern/{filename}", drawTexture.EncodeToPNG());
    }
}

```

</div>
</details>

# おわりに
いかがでしたか？ハーフトーニングって面白いでしょう？
簡単な画像処理ならUnityでも強引に実装できるんですね！
それではまたこんど～