混ぜる割合を出すとき2で割っているのは、全体の半分が最大になるようにってことかなあ、全体ってのは4マスのことで、もし2で割らないと遠い色なのに半分以上のマスを塗ってしまうことになる
using System;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
namespace _20190224_パターンディザ_任意の2色減色
{
<summary>
</summary>
public partial class MainWindow : Window
{
BitmapSource MyBitmapSource;
public MainWindow()
{
InitializeComponent();
var info = System.Diagnostics.FileVersionInfo.GetVersionInfo(System.Reflection.Assembly.GetExecutingAssembly().Location);
Title = info.ProductName;
string imagePath = @"D:\ブログ用\チェック用2\NEC_6008_2018_11_25_午後わてん.jpg";
byte[] vs;
(vs, MyBitmapSource) = MakeByteArrayAndSourceFromImageFile(imagePath, PixelFormats.Rgb24, 96, 96);
MyImage.Source = Dither2(MyBitmapSource);
}
private BitmapSource Dither2(BitmapSource bitmapSource)
{
byte r1, g1, b1, r2, g2, b2;
r1 = 66; g1 = 70; b1 = 55;
r2 = 171; g2 = 178; b2 = 146;
double[][] thresholdMatrix = MakeThresholdMatrix4x4();
int xx = thresholdMatrix[0].Length;
int yy = thresholdMatrix.Length;
var wb = new WriteableBitmap(bitmapSource);
int w = wb.PixelWidth;
int h = wb.PixelHeight;
int stride = wb.BackBufferStride;
byte[] pixels = new byte[h * stride];
wb.CopyPixels(pixels, stride, 0);
long p = 0;
for (int y = 0; y < h; y++)
{
for (int x = 0; x < w; x++)
{
p = y * stride + (x * 3);
byte rr = pixels[p];
byte gg = pixels[p + 1];
byte bb = pixels[p + 2];
double distance1 = GetColorDistance(rr, gg, bb, r1, g1, b1);
double distance2 = GetColorDistance(rr, gg, bb, r2, g2, b2);
if (distance1 != 0 & distance2 != 0)
{
double threshold = 0;
if (distance2 > distance1)
{
threshold = distance1 / distance2 / 2.0;
if (threshold > thresholdMatrix[y % yy][x % xx])
{
pixels[p] = r2; pixels[p + 1] = g2; pixels[p + 2] = b2;
}
else
{
pixels[p] = r1; pixels[p + 1] = g1; pixels[p + 2] = b1;
}
}
else
{
threshold = distance2 / distance1 / 2.0;
if (threshold > thresholdMatrix[y % yy][x % xx])
{
pixels[p] = r1; pixels[p + 1] = g1; pixels[p + 2] = b1;
}
else
{
pixels[p] = r2; pixels[p + 1] = g2; pixels[p + 2] = b2;
}
}
}
}
}
wb.WritePixels(new Int32Rect(0, 0, w, h), pixels, stride, 0);
return wb;
}
private double GetColorDistance(byte r1, byte g1, byte b1, byte r2, byte g2, byte b2)
{
return Math.Sqrt(Math.Pow(r2 - r1, 2) + Math.Pow(g2 - g1, 2) + Math.Pow(b2 - b1, 2));
}
#region ディザパターン作成
private double[][] MakeThresholdMatrix2x2()
{
double[][] thresholdMatrix = new double[][]
{
new double[] { 1f / 5f, 3f / 5f },
new double[] { 4f / 5f, 2f / 5f }
};
return thresholdMatrix;
}
private double[][] MakeThresholdMatrix4x4()
{
double[][] thresholdMap = new double[][]
{
new double[] { 1f / 17f, 13f / 17f, 4f / 17f, 16f / 17f },
new double[] { 9f / 17f, 5f / 17f, 12f / 17f, 8f / 17f },
new double[] { 3f / 17f, 15f / 17f, 2f / 17f, 14f / 17f },
new double[] { 11f / 17f, 7f / 17f, 10f / 17f, 6f / 17f }
};
return thresholdMap;
}
private double[][] MakeThresholdMatrixMagicSquare()
{
double[][] thresholdMap = new double[][]
{
new double[] { 1f / 17f, 15f / 17f, 14f / 17f, 4f / 17f },
new double[] { 8f / 17f, 10f / 17f, 11f / 17f, 5f / 17f },
new double[] { 12f / 17f, 6f / 17f, 7f / 17f, 9f / 17f },
new double[] { 13f / 17f, 3f / 17f, 2f / 17f, 16f / 17f }
};
return thresholdMap;
}
private double[][] MakeThresholdMatrixCompletenesSquare()
{
double[][] thresholdMap = new double[][]
{
new double[] { 1f / 17f, 8f / 17f, 13f / 17f, 12f / 17f },
new double[] { 14f / 17f, 11f / 17f, 2f / 17f, 7f / 17f },
new double[] { 4f / 17f, 5f / 17f, 16f / 17f, 9f / 17f },
new double[] { 15f / 17f, 10f / 17f, 3f / 17f, 6f / 17f }
};
return thresholdMap;
}
private double[][] MakeThresholdMatrixCompletenes7x7()
{
double[][] thresholdMap = new double[][]
{
new double[] { 1, 37, 24, 11, 47, 34, 21 },
new double[] { 13, 49, 29, 16, 3, 39, 26 },
new double[] { 18, 5, 41, 28, 8, 44, 31 },
new double[] { 23, 10, 46, 33, 20, 7, 36 },
new double[] { 35, 15, 2, 38, 25, 12, 48 },
new double[] { 40, 27, 14, 43, 30, 17, 4 },
new double[] { 45, 32, 19, 6, 42, 22, 9 },
};
for(int i = 0; i < thresholdMap.Length; i++)
{
for (int j = 0; j < thresholdMap[i].Length; j++)
{
thresholdMap[i][j] /= 50.0;
}
}
return thresholdMap;
}
#endregion
<summary>
</summary>
<param name="width"></param>
<param name="height"></param>
<param name="red"></param>
<param name="green"></param>
<param name="blue"></param>
<returns></returns>
private BitmapSource MakeBitmap(int width, int height, byte red, byte green, byte blue)
{
var wb = new WriteableBitmap(width, height, 96, 96, PixelFormats.Rgb24, null);
int stride = wb.BackBufferStride;
byte[] pixels = new byte[height * stride];
for (int i = 0; i < pixels.Length; i += 3)
{
pixels[i] = red;
pixels[i + 1] = green;
pixels[i + 2] = blue;
}
wb.WritePixels(new Int32Rect(0, 0, width, height), pixels, stride, 0);
return wb;
}
private byte[] BitmapToByteArray(BitmapSource source)
{
int stride = source.Format.BitsPerPixel / 8 * source.PixelWidth;
byte[] pixels = new byte[source.PixelHeight * stride];
source.CopyPixels(pixels, stride, 0);
return pixels;
}
<summary>
</summary>
<param name="filePath"></param>
<param name="pixelFormat"></param>
<param name="dpiX"></param>
<param name="dpiY"></param>
<returns></returns>
private (byte[] array, BitmapSource source) MakeByteArrayAndSourceFromImageFile(string filePath, PixelFormat pixelFormat, double dpiX = 0, double dpiY = 0)
{
byte[] pixels = null;
BitmapSource source = null;
try
{
using (System.IO.FileStream fs = new System.IO.FileStream(filePath, System.IO.FileMode.Open, System.IO.FileAccess.Read))
{
var bf = BitmapFrame.Create(fs);
var convertedBitmap = new FormatConvertedBitmap(bf, pixelFormat, null, 0);
int w = convertedBitmap.PixelWidth;
int h = convertedBitmap.PixelHeight;
int stride = (w * pixelFormat.BitsPerPixel + 7) / 8;
pixels = new byte[h * stride];
convertedBitmap.CopyPixels(pixels, stride, 0);
if (dpiX == 0) { dpiX = bf.DpiX; }
if (dpiY == 0) { dpiY = bf.DpiY; }
source = BitmapSource.Create(
w, h, dpiX, dpiY,
convertedBitmap.Format,
convertedBitmap.Palette, pixels, stride);
};
}
catch (Exception)
{
}
return (pixels, source);
}
}
}