1020
This commit is contained in:
@@ -0,0 +1,238 @@
|
||||
using SkiaSharp;
|
||||
|
||||
namespace DigitalImageProcessing
|
||||
{
|
||||
internal class Alograms
|
||||
{
|
||||
public static void Steps(string outputDirectoryPath, string filename)
|
||||
{
|
||||
int blockSize = 16;
|
||||
|
||||
using SKBitmap bitmap = SKBitmap.Decode(filename);
|
||||
|
||||
using SKBitmap avgGraph = new(bitmap.Width, bitmap.Height);
|
||||
using SKCanvas avgCanvas = new(avgGraph);
|
||||
|
||||
float[,] gray = new float[bitmap.Width, bitmap.Height];
|
||||
float[,] xgradient = new float[bitmap.Width, bitmap.Height];
|
||||
float[,] ygradient = new float[bitmap.Width, bitmap.Height];
|
||||
float[,] fequency = new float[bitmap.Width, bitmap.Height];
|
||||
float[,] angle = new float[bitmap.Width, bitmap.Height];
|
||||
//float[,] direction = new float[bitmap.Width, bitmap.Height];
|
||||
|
||||
for (int y = 0; y < bitmap.Height; y++)
|
||||
for (int x = 0; x < bitmap.Width; x++)
|
||||
{
|
||||
SKColor color = bitmap.GetPixel(x, y);
|
||||
|
||||
// gray
|
||||
gray[x, y] = (color.Red + color.Green + color.Blue) / 3f / 256f;
|
||||
}
|
||||
|
||||
for (int y = 0; y < bitmap.Height; y++)
|
||||
for (int x = 0; x < bitmap.Width; x++)
|
||||
{
|
||||
// gradient
|
||||
if (x > 0 && x < bitmap.Width - 1)
|
||||
xgradient[x, y] = (gray[x + 1, y] - gray[x - 1, y]) / 2f;
|
||||
if (y > 0 && y < bitmap.Height - 1)
|
||||
ygradient[x, y] = (gray[x, y + 1] - gray[x, y - 1]) / 2f;
|
||||
fequency[x, y] = float.Sqrt((xgradient[x, y] * xgradient[x, y]) + (ygradient[x, y] * ygradient[x, y]));
|
||||
if (fequency[x, y] == 0)
|
||||
continue;
|
||||
angle[x, y] = float.Atan2(ygradient[x, y], xgradient[x, y]);
|
||||
int blockx = x / blockSize;
|
||||
int blocky = y / blockSize;
|
||||
float dirx = float.Cos(angle[x, y]);
|
||||
float diry = float.Sin(angle[x, y]);
|
||||
avgCanvas.DrawLine(
|
||||
(blockx + 0.5f - (diry / 2)) * blockSize,
|
||||
(blocky + 0.5f - (-dirx / 2)) * blockSize,
|
||||
(blockx + 0.5f + (diry / 2)) * blockSize,
|
||||
(blocky + 0.5f + (-dirx / 2)) * blockSize,
|
||||
new SKPaint { Color = SKColors.Red.WithAlpha((byte)(fequency[x, y] * 64)), StrokeWidth = 1 });
|
||||
}
|
||||
|
||||
using FileStream fs = new(outputDirectoryPath + @"avgGraph.png", FileMode.Create, FileAccess.Write);
|
||||
avgGraph.Encode(fs, SKEncodedImageFormat.Png, 100);
|
||||
|
||||
xgradient.DrawTo(outputDirectoryPath + @"xgradient.png");
|
||||
ygradient.DrawTo(outputDirectoryPath + @"ygradient.png");
|
||||
fequency.DrawTo(outputDirectoryPath + @"fequency.png");
|
||||
angle.DrawTo(outputDirectoryPath + @"angle.png");
|
||||
}
|
||||
public static void Noises(string filepath)
|
||||
{
|
||||
using SKBitmap bitmap = new(1024, 1024);//SKBitmap.Decode(filepath);
|
||||
using SKCanvas canvas = new SKCanvas(bitmap);
|
||||
canvas.Clear(SKColors.Black);
|
||||
const int gap = 128;
|
||||
canvas.DrawRect(new SKRectI(gap, gap, 1024 - gap, 1024 - gap), new SKPaint()
|
||||
{
|
||||
Color = SKColors.Gray,
|
||||
Style = SKPaintStyle.Fill,
|
||||
});
|
||||
canvas.DrawCircle(512, 512, 256, new SKPaint()
|
||||
{
|
||||
Color = SKColors.White,
|
||||
Style = SKPaintStyle.Fill,
|
||||
});
|
||||
|
||||
using FileStream stream = new(@"C:\Users\Surface\Downloads\" + @"original.png", FileMode.Create, FileAccess.Write);
|
||||
bitmap.Encode(stream, SKEncodedImageFormat.Png, 100);
|
||||
|
||||
using SKBitmap noiseBitmap = new(bitmap.Width, bitmap.Height);
|
||||
using SKCanvas noiseCanvas = new(noiseBitmap);
|
||||
Func<byte, byte> noiseFunc = (v) => ApplyGaussianToRandomValue(new(), v, 10f);//NoiseFuncs.Gaussian(v, new Random(), 20f);
|
||||
int[] changes = new int[256];
|
||||
//NoiseFuncs.GetFunc(NoiseType.Gaussian, new Random());
|
||||
for (int x = 0; x < bitmap.Width; x++)
|
||||
for (int y = 0; y < bitmap.Height; y++)
|
||||
{
|
||||
byte noised = noiseFunc(bitmap.GetPixel(x, y).Red);
|
||||
noiseBitmap.SetPixel(x, y,
|
||||
new SKColor(
|
||||
noised,
|
||||
noised,
|
||||
noised));
|
||||
changes[noised]++;
|
||||
}
|
||||
using FileStream fs = new(@"C:\Users\Surface\Downloads\" + @"noise.png", FileMode.Create, FileAccess.Write);
|
||||
noiseBitmap.Encode(fs, SKEncodedImageFormat.Png, 100);
|
||||
|
||||
using SKBitmap c = new(256, 256);
|
||||
using SKCanvas cc = new(c);
|
||||
cc.Clear(SKColors.Black);
|
||||
int max = changes[1..].Max() + 1;
|
||||
for (int i = 0; i < 255; i++)
|
||||
{
|
||||
cc.DrawLine(i, 256, i, 256 - (changes[i] * 256 / max), new SKPaint()
|
||||
{
|
||||
Color = i is 0 or 127 or 255 ? SKColors.Red : SKColors.White,
|
||||
StrokeWidth = 1,
|
||||
});
|
||||
//cc.DrawLine(i, 256, i, 256 - (NoiseFuncs.gaussianKerel[i] * 256), new SKPaint()
|
||||
//{
|
||||
// Color = SKColors.LightBlue.WithAlpha(127),
|
||||
// StrokeWidth = 1,
|
||||
//});
|
||||
}
|
||||
using FileStream fsc = new(@"C:\Users\Surface\Downloads\" + @"changes.png", FileMode.Create, FileAccess.Write);
|
||||
c.Encode(fsc, SKEncodedImageFormat.Png, 100);
|
||||
}
|
||||
public static byte ApplyGaussianToRandomValue(Random random, float mean, float sigma)
|
||||
{
|
||||
// Generate a random value using the Box-Muller transform
|
||||
double u1 = 1.0 - random.NextDouble(); // Uniform(0,1] random doubles
|
||||
double u2 = 1.0 - random.NextDouble();
|
||||
double standardNormal = Math.Sqrt(-2.0 * Math.Log(u1)) * Math.Sin(2.0 * Math.PI * u2);
|
||||
|
||||
// Scale the standard normal value to the desired mean and standard deviation
|
||||
double gaussianValue = mean + sigma * standardNormal;
|
||||
|
||||
// Clamp the result to the byte range [0, 255]
|
||||
return (byte)Math.Clamp((int)gaussianValue, 0, 255);
|
||||
}
|
||||
}
|
||||
public static class NoiseFuncs
|
||||
{
|
||||
//public static Func<byte, byte> GetFunc(NoiseType type, Random random)
|
||||
//{
|
||||
// return type switch
|
||||
// {
|
||||
// NoiseType.SaltAndPepper => (value) => SaltAndPepper(value, random, 0.05f),
|
||||
// NoiseType.Gaussian => (value) => Gaussian(value, random, 256f),
|
||||
// _ => throw new NotImplementedException(),
|
||||
// };
|
||||
//}
|
||||
public static byte SaltAndPepper(byte value, Random random, float amount)
|
||||
{
|
||||
float r = (float)random.NextDouble();
|
||||
if (r < amount / 2)
|
||||
return 0;
|
||||
else if (r < amount)
|
||||
return 255;
|
||||
else
|
||||
return value;
|
||||
}
|
||||
public static float[] gaussianKerel = [];
|
||||
public static void InitGaussianKernel(float sigma)
|
||||
{
|
||||
gaussianKerel = new float[256];
|
||||
for (int i = 0; i < 256; i++)
|
||||
{
|
||||
gaussianKerel[i] = GaussianKernel(i, 127, sigma);
|
||||
}
|
||||
//for (int i = 1; i < 256; i++)
|
||||
//{
|
||||
// gaussianKerel[i] += gaussianKerel[i - 1];
|
||||
//}
|
||||
}
|
||||
public static byte Gaussian(byte value, Random random, float sigma)
|
||||
{
|
||||
if (gaussianKerel.Length == 0)
|
||||
InitGaussianKernel(sigma);
|
||||
|
||||
//int randomIndex = random.Next(0, 256);
|
||||
float r = random.NextSingle();
|
||||
float f = value* GaussianKernel(r * 255, value, sigma);
|
||||
int newValue = (int)f;//(int)(value + (32 * (f)));
|
||||
return (byte)Math.Clamp(newValue, 0, 255);
|
||||
}
|
||||
private static float GaussianKernel(float value, float mu, float sigma)
|
||||
{
|
||||
float exp = -(value - mu) * (value - mu) / (2 * sigma * sigma);
|
||||
float peak = 1 / (sigma * float.Sqrt(2 * float.Pi));
|
||||
return peak * float.Exp(exp);
|
||||
}
|
||||
public static byte Rayleigh(byte value, Random random, float sigma)
|
||||
{
|
||||
double u = 1.0 - random.NextDouble();
|
||||
double noise = sigma * Math.Sqrt(-2.0 * Math.Log(u));
|
||||
int newValue = (int)(value + noise);
|
||||
if (newValue < 0) newValue = 0;
|
||||
if (newValue > 255) newValue = 255;
|
||||
return (byte)newValue;
|
||||
}
|
||||
public static byte Gamma(byte value, Random random)
|
||||
{
|
||||
double u = 1.0 - random.NextDouble();
|
||||
double noise = -Math.Log(u);
|
||||
int newValue = (int)(value + noise);
|
||||
if (newValue < 0) newValue = 0;
|
||||
if (newValue > 255) newValue = 255;
|
||||
return (byte)newValue;
|
||||
}
|
||||
}
|
||||
//public static class FilterFuncs
|
||||
//{
|
||||
// public static Func<SKBitmap, SKSizeI, byte> GetFunc()
|
||||
// {
|
||||
|
||||
// }
|
||||
// private static byte Mean(SKBitmap bitmap, SKRectI size, Func<SKColor, byte> channel)
|
||||
// {
|
||||
// for(int x=size.Left;x<=size.Right;x++)
|
||||
// for(int y=size.Top; y <= size.Bottom; y++)
|
||||
// {
|
||||
// byte value = channel(bitmap.GetPixel(x, y));
|
||||
|
||||
// }
|
||||
// }
|
||||
// private static byte Median(SKBitmap bitmap, SKRectI size)
|
||||
// {
|
||||
// }
|
||||
|
||||
//}
|
||||
public enum NoiseType
|
||||
{
|
||||
SaltAndPepper,
|
||||
Gaussian,
|
||||
Rayleigh,
|
||||
}
|
||||
//public enum FilterType
|
||||
//{
|
||||
// Mean,
|
||||
// Median,
|
||||
//}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DigitalImageProcessing
|
||||
{
|
||||
internal class Noise
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,61 +1,7 @@
|
||||
using DigitalImageProcessing;
|
||||
using SkiaSharp;
|
||||
|
||||
string filename = @"E:\Download\a7522809e76767bec27db9650365c56a.jpeg";
|
||||
|
||||
int blockSize = 16;
|
||||
|
||||
using SKBitmap bitmap = SKBitmap.Decode(filename);
|
||||
using SKCanvas canvas = new(bitmap);
|
||||
|
||||
using SKBitmap avgGraph = new(bitmap.Width, bitmap.Height);
|
||||
using SKCanvas avgCanvas = new(avgGraph);
|
||||
|
||||
float[,] gray = new float[bitmap.Width, bitmap.Height];
|
||||
float[,] xgradient = new float[bitmap.Width, bitmap.Height];
|
||||
float[,] ygradient = new float[bitmap.Width, bitmap.Height];
|
||||
float[,] fequency = new float[bitmap.Width, bitmap.Height];
|
||||
float[,] angle = new float[bitmap.Width, bitmap.Height];
|
||||
//float[,] direction = new float[bitmap.Width, bitmap.Height];
|
||||
|
||||
for (int y = 0; y < bitmap.Height; y++)
|
||||
for (int x = 0; x < bitmap.Width; x++)
|
||||
{
|
||||
SKColor color = bitmap.GetPixel(x, y);
|
||||
|
||||
// gray
|
||||
gray[x, y] = (color.Red + color.Green + color.Blue) / 3f / 256f;
|
||||
}
|
||||
|
||||
for (int y = 0; y < bitmap.Height; y++)
|
||||
for (int x = 0; x < bitmap.Width; x++)
|
||||
{
|
||||
// gradient
|
||||
if (x > 0 && x < bitmap.Width - 1)
|
||||
xgradient[x, y] = (gray[x + 1, y] - gray[x - 1, y]) / 2f;
|
||||
if (y > 0 && y < bitmap.Height - 1)
|
||||
ygradient[x, y] = (gray[x, y + 1] - gray[x, y - 1]) / 2f;
|
||||
fequency[x, y] = float.Sqrt(xgradient[x, y] * xgradient[x, y] + ygradient[x, y] * ygradient[x, y]);
|
||||
if (fequency[x, y] == 0)
|
||||
continue;
|
||||
angle[x, y] = float.Atan2(ygradient[x, y], xgradient[x, y]);
|
||||
int blockx = x / blockSize;
|
||||
int blocky = y / blockSize;
|
||||
float dirx = float.Cos(angle[x, y]);
|
||||
float diry = float.Sin(angle[x, y]);
|
||||
avgCanvas.DrawLine(
|
||||
(blockx + 0.5f - diry / 2) * blockSize,
|
||||
(blocky + 0.5f - -dirx / 2) * blockSize,
|
||||
(blockx + 0.5f + diry / 2) * blockSize,
|
||||
(blocky + 0.5f + -dirx / 2) * blockSize,
|
||||
new SKPaint { Color = SKColors.Red.WithAlpha((byte)(fequency[x, y] * 64)), StrokeWidth = 1 });
|
||||
}
|
||||
|
||||
using FileStream fs = new(@"E:\Download\avgGraph.png", FileMode.Create, FileAccess.Write);
|
||||
avgGraph.Encode(fs, SKEncodedImageFormat.Png, 100);
|
||||
|
||||
xgradient.DrawTo(@"E:\Download\xgradient.png");
|
||||
ygradient.DrawTo(@"E:\Download\ygradient.png");
|
||||
fequency.DrawTo(@"E:\Download\fequency.png");
|
||||
angle.DrawTo(@"E:\Download\angle.png");
|
||||
string testImage = @"C:\Users\Surface\Downloads\" + @"1682575881230001.png";
|
||||
//Alograms.Steps(@"C:\Users\Surface\Downloads\", @"C:\Users\Surface\Downloads\" + @"1682575881230001.png");
|
||||
|
||||
Alograms.Noises(testImage);
|
||||
@@ -0,0 +1,35 @@
|
||||
using SkiaSharp;
|
||||
|
||||
namespace DigitalImageProcessing
|
||||
{
|
||||
internal enum SamplerMethod
|
||||
{
|
||||
None = 0,
|
||||
Repeat = 1,
|
||||
Mirror = 2,
|
||||
Clamp = 3,
|
||||
}
|
||||
internal class Sampler
|
||||
{
|
||||
private SKBitmap bitmap;
|
||||
public SamplerMethod Method { get; set; }
|
||||
public Sampler(SKBitmap bitmap)
|
||||
{
|
||||
this.bitmap = bitmap;
|
||||
}
|
||||
public SKColor this[int x, int y]
|
||||
{
|
||||
get
|
||||
{
|
||||
return Method switch
|
||||
{
|
||||
SamplerMethod.None => bitmap.GetPixel(x, y),
|
||||
SamplerMethod.Repeat => bitmap.GetPixel((x + bitmap.Width) % bitmap.Width, (y + bitmap.Height) % bitmap.Height),
|
||||
|
||||
SamplerMethod.Clamp => bitmap.GetPixel(int.Clamp(x, 0, bitmap.Width - 1), int.Clamp(y, 0, bitmap.Height - 1)),
|
||||
SamplerMethod.Mirror or _ => throw new NotImplementedException(),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user