Last active
December 19, 2015 14:39
-
-
Save lobrien/5971032 to your computer and use it in GitHub Desktop.
Simple convolution filter: First convert byte[,] to double[,] using .ToRangePlusOrMinusOne() and then use Convolve3x3(). Then convert back to byte[,] using ToBytes()
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public static double[,] ToRangePlusOrMinusOne(this byte[,] self) | |
{ | |
var ySize = self.GetLength(1); | |
var xSize = self.GetLength(0); | |
var dArr = new double[ySize, xSize]; | |
for(var y = 0; y < ySize; y++) | |
{ | |
for(var x = 0; x < xSize; x++) | |
{ | |
dArr[y, x] = self[y, x].ToRangePlusOrMinusOne(); | |
} | |
} | |
return dArr; | |
} | |
public static double[] ToRangePlusOrMinusOne(this byte[] self) | |
{ | |
var newArray = new double[self.Length]; | |
for(int i = 0; i < self.Length; i++) | |
{ | |
newArray[i] = self[i].ToRangePlusOrMinusOne(); | |
} | |
return newArray; | |
} | |
public static double ToRangePlusOrMinusOne(this byte self) | |
{ | |
var percent = self * 1.0 / byte.MaxValue; | |
return 2.0 * (percent - 0.5); | |
} | |
/* Convolutes whole array -- copies edge-values to the off-by-one external location | |
*/ | |
public static double[,] Convolve3x3(this double[,] self, double[,] kernel) | |
{ | |
var xSize = self.GetLength(1); | |
var ySize = self.GetLength(0); | |
var newBlock = new double[ySize, xSize]; | |
for(var y = 0; y < ySize; y++) | |
{ | |
for(var x = 0; x < xSize; x++) | |
{ | |
var upY = y == 0 ? y : y - 1; | |
var leftX = x == 0 ? x : x - 1; | |
var downY = y == ySize - 1 ? y : y + 1; | |
var rightX = x == xSize - 1 ? x : x + 1; | |
double upLeftK = kernel[0, 0] * self[upY, leftX]; | |
double upK = kernel[0, 1] * self[upY, x]; | |
double upRightK = kernel[0, 2] * self[upY, rightX]; | |
double leftK = kernel[1, 0] * self[y, leftX]; | |
double centerK = kernel[1, 1] * self[y, x]; | |
double rightK = kernel[1, 2] * self[y, rightX]; | |
double downLeftK = kernel[2, 0] * self[downY, leftX]; | |
double downK = kernel[2, 1] * self[downY, x]; | |
double downRightK = kernel[2, 2] * self[downY, rightX]; | |
var sum = upLeftK + upK + upRightK + leftK + centerK + rightK + downLeftK + downK + downRightK; | |
var avg = sum / 9; | |
avg = avg < 0 ? 0 : avg > 255.0 ? 255 : avg; | |
newBlock[y, x] = (double)avg; | |
} | |
} | |
return newBlock; | |
} | |
/* | |
Grrr... Can't Range<U,T> because no generic extensions and can't Range<T> because no T - T | |
How much lovelier would be: | |
from s in self select low + ((high -low) * (s - Min(self)) / (Max(self) - Min(self))); | |
*/ | |
public static byte[,] ToBytes(this double[,] self) | |
{ | |
//No Min and Max extension methods for rect arrays | |
var selfMin = double.MaxValue; | |
var selfMax = double.MinValue; | |
for(var y = 0; y < self.GetLength(0); y++) | |
{ | |
for(var x = 0; x < self.GetLength(1); x++) | |
{ | |
if(self[y, x] < selfMin) | |
{ | |
selfMin = self[y, x]; | |
} | |
if(self[y, x] > selfMax) | |
{ | |
selfMax = self[y, x]; | |
} | |
} | |
} | |
var range = byte.MaxValue; | |
var ary = new byte[self.GetLength(0), self.GetLength(1)]; | |
for(var y = 0; y < self.GetLength(0); y++) | |
{ | |
for(var x = 0; x < self.GetLength(1); x++) | |
{ | |
var c = ((range) * (self[y, x] - selfMin) / (selfMax - selfMin)); | |
if(c < byte.MinValue) | |
{ | |
c = byte.MinValue; | |
} | |
if(c > byte.MaxValue) | |
{ | |
c = byte.MaxValue; | |
} | |
ary[y, x] = (byte)c; | |
} | |
} | |
return ary; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment