ハーフトーニングとは?
みなさんはプリンターを使ったことはありますか?あのコピーとか印刷とかをやってくれるあれです。もちろん使ったことありますよね?
最近のプリンターは家庭用でもカラープリントができるようになりましたよね。
しかし、原始的なプリンターにはカラープリント機能は無く、印刷対象に対して「インクを出す」という行為と「インクを出さない」という2つの機能しかありませんでした。
ここで、あることが問題になります。それは「白黒の濃淡をどう表現するか」という問題です。
原始的なプリンタはインクを出すか出さないかの2つの行動しかとれず、少しだけインクを出すなんてこともできません。
この問題を解決する手法がハーフトーニングです。ずばり、白インクと黒インクの打ち方を工夫することで、あたかも濃淡がついているように見せる技術といったところでしょうか。
有名なハーフトーニング
有名なハーフトーニングの中でも今回は以下の3つについてお話します。
- 濃度パターン法
- ディザ法
- 誤差拡散法
濃度パターン法
元画像の4 * 4画素を17諧調に分類し、諧調に対応する 4 * 4 画素のパターンで置き換え、2値画像(モノクロ画像)で表す方式。
・メリット
17諧調で表現できる
・デメリット
画像が荒くなる
ディザ法
元画像を4 * 4の領域で処理し、画素ごとに異なる基準値を用いる方式。
・メリット
解像度(画像サイズ)を維持できる
・デメリット
繰り返しパターンが目立つ
誤差拡散法
ある画素の基準値からの誤差を周辺の画素に伝播させ、誤差を軽減する方式。
・メリット
誤差を周りの画素に伝播させるため比較的正しく表現できる
解像度(画像サイズ)を維持できる
・デメリット
画像のざらざら感が増える(語彙力)
Unityで実装する
さっそく実装していきましょう!
おおまかな処理は、
- スクリプトがアタッチされているオブジェクトのSpriteのTextureを取得する
- 取得したTextureのピクセル情報を配列Aに格納する
- ピクセルのグレイスケール化とピクセルの諧調に対するパターンを新しい配列Bに格納する
- Textureを配列Bで更新する
- Textureをpng形式で画像を保存する
です。頑張ってコードを書いていきましょう。
濃度パターン法
はいそして出来上がったものがこちらになります。コードが非常に長いので折りたためるようにしてあります。
※実行するときにかなり重くなりますので注意!
濃度パターン法(DensityPattern_Logic)のコード
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());
}
}
ディザ法
コードが非常に長いので折りたためるようにしてあります。
ディザ法(Dither_Logic)のコード
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());
}
}
誤差拡散法
コードが非常に長いので折りたためるようにしてあります。
誤差拡散法(ErrorDiffusion_Logic)のコード
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());
}
}
おわりに
いかがでしたか?ハーフトーニングって面白いでしょう?
簡単な画像処理ならUnityでも強引に実装できるんですね!
それではまたこんど~