I am using the following Kernel,
double[,] kernel = new double[,] { { -1, -1, -1, },
{ -1, 9, -1, },
{ -1, -1, -1, }, };
The following code seems to be blurring the input image, rather than Sharpening.
What could have been the issue here?
Here is the entire VS2013 solution.
The original image,
The resulting blurred image,
I have written the following code to Sharpen an image,
public static Bitmap FftSharpen(Bitmap image, double [,] mask)
{
if (image.PixelFormat == PixelFormat.Format8bppIndexed)
{
Bitmap imageClone = (Bitmap)image.Clone();
double[,] maskClone = (double[,])mask.Clone();
Complex[,] cPaddedImage = ImageDataConverter.ToComplex(imageClone);
Complex[,] cPaddedMask = ImageDataConverter.ToComplex(maskClone);
Complex[,] cConvolved = Convolution.Convolve(cPaddedImage, cPaddedMask);
return ImageDataConverter.ToBitmap(cConvolved);
}
else
{
throw new Exception("not a grascale");
}
}
.
.
P.S.
The following is my convolution code,
public static class Convolution
{
public static Complex[,] Convolve(Complex[,] image, Complex[,] mask)
{
Complex[,] convolve = null;
int imageWidth = image.GetLength(0);
int imageHeight = image.GetLength(1);
int maskWidth = mask.GetLength(0);
int maskeHeight = mask.GetLength(1);
if (imageWidth == maskWidth && imageHeight == maskeHeight)
{
FourierTransform ftForImage = new FourierTransform(image); ftForImage.ForwardFFT();
FourierTransform ftForMask = new FourierTransform(mask); ftForMask.ForwardFFT();
Complex[,] fftImage = ftForImage.FourierImageComplex;
Complex[,] fftKernel = ftForMask.FourierImageComplex;
Complex[,] fftConvolved = new Complex[imageWidth, imageHeight];
for (int j = 0; j < imageHeight; j++)
{
for (int i = 0; i < imageWidth; i++)
{
fftConvolved[i, j] = fftImage[i, j] * fftKernel[i, j];
}
}
FourierTransform ftForConv = new FourierTransform();
ftForConv.InverseFFT(fftConvolved);
convolve = ftForConv.GrayscaleImageComplex;
Rescale(convolve);
convolve = FourierShifter.FFTShift(convolve);
}
else
{
throw new Exception("padding needed");
}
return convolve;
}
//Rescale values between 0 and 255.
private static void Rescale(Complex[,] convolve)
{
int imageWidth = convolve.GetLength(0);
int imageHeight = convolve.GetLength(1);
double maxAmp = 0.0;
for (int j = 0; j < imageHeight; j++)
{
for (int i = 0; i < imageWidth; i++)
{
maxAmp = Math.Max(maxAmp, convolve[i, j].Magnitude);
}
}
double scale = 255.0 / maxAmp;
for (int j = 0; j < imageHeight; j++)
{
for (int i = 0; i < imageWidth; i++)
{
convolve[i, j] = new Complex(convolve[i, j].Real * scale, convolve[i, j].Imaginary * scale);
maxAmp = Math.Max(maxAmp, convolve[i, j].Magnitude);
}
}
}
}
Similarly to your other question, the kernel is obtained from an unsigned Bitmap which result in the effective kernel
255 255 255
255 9 255
255 255 255
instead of the expected
-1 -1 -1
-1 9 -1
-1 -1 -1
A solution would again be to convert the bitmap to signed values. Alternatively, since the code provided in this question also supports the numerical kernel to be provided directly to FftSharpen, you could pad _numericalKernel with:
public class MatrixPadder
{
public static double[,] Pad(double[,] image, int newWidth, int newHeight)
{
int width = image.GetLength(0);
int height = image.GetLength(1);
/*
It is always guaranteed that,
width < newWidth
and
height < newHeight
*/
if ((width < newWidth && height < newHeight)
|| (width < newWidth && height == newHeight)
|| (width == newWidth && height < newHeight))
{
double[,] paddedImage = new double[newWidth, newHeight];
int startPointX = (int)Math.Ceiling((double)(newWidth - width) / (double)2) - 1;
int startPointY = (int)Math.Ceiling((double)(newHeight - height) / (double)2) - 1;
for (int y = startPointY; y < (startPointY + height); y++)
{
for (int x = startPointX; x < (startPointX + width); x++)
{
int xxx = x - startPointX;
int yyy = y - startPointY;
paddedImage[x, y] = image[xxx, yyy];
}
}
return paddedImage;
}
else if (width == newWidth && height == newHeight)
{
return image;
}
else
{
throw new Exception("Pad() -- threw an exception");
}
}
}
which you could call from filterButton_Click using:
if (_convolutionType == ConvolutionType.FFT)
{
double[,] paddedmask = MatrixPadder.Pad(_numericalKernel,
_paddedImage.Width,
_paddedImage.Height);
sharpened = SharpenFilter.FftSharpen(_paddedImage, paddedmask);
}
Also adjusting the Rescale function as shown in my other answer should then give you the desired sharpened image:
Related
Store an image with the ".raw" extension in a two-dimensional byte array. Convert it to bitmap. I want to show this in the picture box, but if I run it with the code below, I get an error that the parameter is wrong.
Width and height are obtained from the information provided by the header file.
I wonder what I'm doing wrong.
string filename = #"test.raw";
byte[] rawBytes = File.ReadAllBytes(filename);
int bytePixel = 2;
int width = samples*bytePixel;
int height = lines;
byte[,] rawData = new byte[height, width];
int counter = new int();
for(int i = 0; i < height; i++)
{
for(int j = 0; j < width; j++, counter++)
{
rawData[i, j] = rawBytes[counter];
}
}
Bitmap bitmapImage = new Bitmap(width, height, PixelFormat.Format16bppGrayScale);
BitmapData bitmapImageData = bitmapImage.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, PixelFormap.Format16bppGrayScale);
unsafe
{
byte* pointer = (byte*)bitmapImageData.Scan0.ToPointer();
for(int y = 0; y < height; y++)
{
for(int x = 0; x < width; x++, pointer++)
{
*pointer = rawData[y, x];
}
}
}
bitmapImage.UnlockBits(bitmapImageData);
pictureBox1.Image = bitmapImage;
Please give me some advice.
I can't figure out what's wrong but if you just want to see byte array result on screen, this func will make bmp file with IntPtr. Hope it helps.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
var fs = new FileStream("test.bmp", FileMode.Open);
Bitmap bitmap = new Bitmap(800, 600, PixelFormat.Format16bppGrayScale);
BitmapData bitmapdata = bitmap.LockBits(new Rectangle(0, 0, 800, 600), ImageLockMode.WriteOnly, PixelFormat.Format16bppGrayScale);
unsafe
{
byte* p = (byte*)bitmapdata.Scan0.ToPointer();
for (int i = 0; i < 600; i++)
{
for (int j = 0; j < 800; j++)
{
*p = (byte)(i * j); p++;
}
}
}
FileSaveBMP($"{DateTime.Now.ToString("yyyyMMddHHmmssfff")}.bmp", bitmapdata.Scan0, new CRect() { Width = 800, Height = 600 }, 800);
bitmap.UnlockBits(bitmapdata);
//pictureBox1.Image = bitmap;
}
private unsafe void FileSaveBMP(string sFile, IntPtr ptr, CRect rect, int w, int p_nByte = 1)
{
FileStream fs = new FileStream(sFile, FileMode.Create, FileAccess.Write);
BinaryWriter bw = new BinaryWriter(fs);
bw.Write(Convert.ToUInt16(0x4d42));
if (p_nByte == 1)
{
if ((Int64)rect.Width * (Int64)rect.Height > Int32.MaxValue) bw.Write(Convert.ToUInt32(54 + 1024 + p_nByte * 1000 * 1000));
else bw.Write(Convert.ToUInt32(54 + 1024 + p_nByte * (Int64)rect.Width * (Int64)rect.Height));
}
else if (p_nByte == 3)
{
if ((Int64)rect.Width * (Int64)rect.Height > Int32.MaxValue) bw.Write(Convert.ToUInt32(54 + p_nByte * 1000 * 1000));//uint bfSize = br.ReadUInt32();
else bw.Write(Convert.ToUInt32(54 + p_nByte * (Int64)rect.Width * (Int64)rect.Height));//uint bfSize = br.ReadUInt32();
}
//image 크기 bw.Write(); bmfh.bfSize = sizeof(14byte) + nSizeHdr + rect.right * rect.bottom;
bw.Write(Convert.ToUInt16(0)); //reserved // br.ReadUInt16();
bw.Write(Convert.ToUInt16(0)); //reserved //br.ReadUInt16();
if (p_nByte == 1)
bw.Write(Convert.ToUInt32(1078));
else if (p_nByte == 3)
bw.Write(Convert.ToUInt32(54));//uint bfOffBits = br.ReadUInt32();
bw.Write(Convert.ToUInt32(40));// uint biSize = br.ReadUInt32();
bw.Write(Convert.ToInt32(rect.Width));// nWidth = br.ReadInt32();
bw.Write(Convert.ToInt32(rect.Height));// nHeight = br.ReadInt32();
bw.Write(Convert.ToUInt16(1));// a = br.ReadUInt16();
bw.Write(Convert.ToUInt16(8 * p_nByte)); //byte // nByte = br.ReadUInt16() / 8;
bw.Write(Convert.ToUInt32(0)); //compress //b = br.ReadUInt32();
if ((Int64)rect.Width * (Int64)rect.Height > Int32.MaxValue) bw.Write(Convert.ToUInt32(1000 * 1000));// b = br.ReadUInt32();
else bw.Write(Convert.ToUInt32((Int64)rect.Width * (Int64)rect.Height));// b = br.ReadUInt32();
bw.Write(Convert.ToInt32(0));//a = br.ReadInt32();
bw.Write(Convert.ToInt32(0));// a = br.ReadInt32();
bw.Write(Convert.ToUInt32(256)); //color //b = br.ReadUInt32();
bw.Write(Convert.ToUInt32(256)); //import // b = br.ReadUInt32();
if (p_nByte == 1)
{
for (int i = 0; i < 256; i++)
{
bw.Write(Convert.ToByte(i));
bw.Write(Convert.ToByte(i));
bw.Write(Convert.ToByte(i));
bw.Write(Convert.ToByte(255));
}
}
if (rect.Width % 4 != 0)
{
rect.Right += 4 - rect.Width % 4;
}
byte[] aBuf = new byte[p_nByte * rect.Width];
for (int i = rect.Height - 1; i >= 0; i--)
{
Marshal.Copy((IntPtr)((long)ptr + rect.Left + ((long)i + (long)rect.Top) * w * p_nByte), aBuf, 0, rect.Width * p_nByte);
bw.Write(aBuf);
}
bw.Close();
fs.Close();
}
}
public class CRect
{
public int Left
{
get; set;
}
public int Right
{
get; set;
}
public int Top
{
get; set;
}
public int Bottom
{
get; set;
}
public int Width
{
get; set;
}
public int Height
{
get; set;
}
}
Above code creates image file like this.
I am trying to split an image of hand written digits into separate ones.
Consider I have this image:
I did a simple logic that could work, but it will and it did encounter a problem:
private static void SplitImages()
{
//We're going to use this code once.. to split our own images into seperate images.. can we do this somehow?
Bitmap testSplitImage = (Bitmap)Bitmap.FromFile("TestSplitImage.jpg");
int[][] imagePixels = new int[testSplitImage.Width][];
for(int i=0;i<imagePixels.Length;i++)
{
imagePixels[i] = new int[testSplitImage.Height];
}
for(int i=0;i<imagePixels.Length;i++)
{
for(int j=0;j<imagePixels[i].Length;j++)
{
Color c = testSplitImage.GetPixel(i, j);
imagePixels[i][j] = (c.R + c.G + c.B) / 3;
}
}
//let's start by getting the first height vector... and count how many of them is white..dunno..
int startColNumber = 0;
int endColNumber = 0;
bool isStart = false;
int imageNumber = 1;
for(int i=0;i<imagePixels.Length;i++)
{
int whiteNumbers = 0;
for(int j=0;j<imagePixels[i].Length;j++)
{
if (imagePixels[i][j] > 200)
{
//consider it white or not really relevant
whiteNumbers++;
}
}
if (whiteNumbers > testSplitImage.Height*95.0/100.0)
{
//let's consider that if a height vector has more than 95% white pixels.. it means that we can start checking for an image
//now if we started checking for the image.. we need to stop
if (isStart)
{
//consider the end of image.. so the end column should be here or we make it +1 at least
endColNumber = i + 1;
isStart = false;
}
}
else
{
if (!isStart)
{
isStart = true; //we will start checking for the image one row before that maybe?
startColNumber = i == 0 ? i : i - 1;
}
}
if (endColNumber > 0)
{
//we got a start and an end.. let's create a new image out of those pixels..hopefully this will work
Bitmap splittedImage = new Bitmap(endColNumber - startColNumber + 1, testSplitImage.Height);
int col = 0;
for(int k=startColNumber;k<=endColNumber;k++)
{
for (int l=0;l<testSplitImage.Height;l++)
{
int c = imagePixels[k][l];
splittedImage.SetPixel(col, l, Color.FromArgb(c, c, c));
}
col++;
}
splittedImage.Save($"Image{imageNumber++}.jpg");
endColNumber = 0;
}
whiteNumbers = 0;
}
}
I did get good results:
I did also get the three zeros:
However, I got this as one image also:
This is one sample of an image that needs to be split (out of 4,000 images mainly), and it's one of the best and easiest one. I am wondering if there's a way to improve my logic, or I should drop this way and find another?
This code only works with monochrome (2 color, black and white) images.
public static class Processor
{
public static byte[] ToArray(this Bitmap bmp) // bitmap to byte array using lockbits
{
Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
BitmapData data = bmp.LockBits(rect, ImageLockMode.ReadWrite, bmp.PixelFormat);
IntPtr ptr = data.Scan0;
int numBytes = data.Stride * bmp.Height;
byte[] bytes = new byte[numBytes];
System.Runtime.InteropServices.Marshal.Copy(ptr, bytes, 0, numBytes);
bmp.UnlockBits(data);
return bytes;
}
public static int GetPixel(this byte[] array, int bpr, int x, int y) //find out if the given pixel is 0 or 1
{
int num = y * bpr + x / 8;
return (array[num] >> 7- x%8) & 1;
}
public static List<Point> getDrawingPoints(this Point start, byte[] array, int width, int height) // get one 0 point (black point) and find all adjacent black points by traveling neighbors
{
List<Point> points = new List<Point>();
points.Add(start);
int BytePerRow = array.Length / bmp.Height;
int counter = 0;
do
{
for (int i = Math.Max(0, points[counter].X - 1); i <= Math.Min(width - 1, points[counter].X + 1); i++)
for (int j = Math.Max(0, points[counter].Y - 1); j <= Math.Min(height - 1, points[counter].Y + 1); j++)
if (array.GetPixel(BytePerRow, i, j) == 0 && !points.Any(p => p.X == i && p.Y == j))
points.Add(new Point(i, j));
counter++;
} while (counter < points.Count);
return points;
}
public static Bitmap ToBitmap(this List<Point> points) // convert points to bitmap
{
int startX = points.OrderBy(p => p.X).First().X,
endX = points.OrderByDescending(p => p.X).First().X,
startY = points.OrderBy(p => p.Y).First().Y,
endY = points.OrderByDescending(p => p.Y).First().Y;
Bitmap bmp = new Bitmap(endX - startX + 1, endY - startY + 1);
Graphics g = Graphics.FromImage(bmp);
g.FillRectangle(new SolidBrush(Color.White), new Rectangle(0, 0, endX - startX - 1, endY - startY - 1));
for (int i = startY; i <= endY; i++)
for (int j = startX; j <= endX; j++)
if (points.Any(p => p.X == j && p.Y == i)) bmp.SetPixel(j - startX, i - startY, Color.Black);
return bmp;
}
}
And use it like this to get all numbers inside the main image:
List<Point> processed = new List<Point>();
Bitmap bmp = ((Bitmap)Bitmap.FromFile(SourceBitmapPath));
byte[] array = bmp.ToArray();
int BytePerRow = array.Length / bmp.Height;
int imgIndex = 1;
for (int i = 0; i < bmp.Width; i++)
for (int j = 0; j < bmp.Height; j++)
{
if (array.GetPixel(BytePerRow, i, j) == 0 && !processed.Any(p => p.X == i && p.Y == j))
{
List<Point> points = new Point(i, j).getDrawingPoints(array, bmp.Width, bmp.Height);
processed.AddRange(points);
Bitmap result = points.ToBitmap();
result.Save($"{imgIndex++}.bmp");
}
}
I'm using paint and Save As monochrome bmp format to generate the source image.
I also tested it with this Image:
that result in the following three images:
I am trying to implement Hough Line Transform.
Input. I am using the following image as input. This single line is expected to produce only one intersection of sine waves in the output.
Desired behavior. my source code is expected to produce the following output as it was generated by the sample application of AForge framework.
Here, we can see:
the dimension of the output is identical to the input image.
the intersection of sine waves are seen at almost at the center.
the intersection pattern of waves is very small and simple.
Present behavior. My source code is producing the following output which is different than that of the output generated by AForge.
the intersection is not at the center.
the wave patterns are also different.
Why is my code producing a different output?
.
Source Code
I have written the following code myself. The following is a Minimal, Complete, and Verifiable source code.
public class HoughMap
{
public int[,] houghMap { get; private set; }
public int[,] image { get; set; }
public void Compute()
{
if (image != null)
{
// get source image size
int inWidth = image.GetLength(0);
int inHeight = image.GetLength(1);
int inWidthHalf = inWidth / 2;
int inHeightHalf = inHeight / 2;
int outWidth = (int)Math.Sqrt(inWidth * inWidth + inHeight * inHeight);
int outHeight = 180;
int outHeightHalf = outHeight / 2;
houghMap = new int[outWidth, outHeight];
// scanning through each (x,y) pixel of the image--+
for (int y = 0; y < inHeight; y++) //|
{ //|
for (int x = 0; x < inWidth; x++)//<-----------+
{
if (image[x, y] != 0)//if a pixel is black, skip it.
{
// We are drawing some Sine waves. So, it may
// vary from -90 to +90 degrees.
for (int theta = -outHeightHalf; theta < outHeightHalf; theta++)
{
double rad = theta * Math.PI / 180;
// respective radius value is computed
//int radius = (int)Math.Round(Math.Cos(rad) * (x - inWidthHalf) - Math.Sin(rad) * (y - inHeightHalf));
//int radius = (int)Math.Round(Math.Cos(rad) * (x + inWidthHalf) - Math.Sin(rad) * (y + inHeightHalf));
int radius = (int)Math.Round(Math.Cos(rad) * (x) - Math.Sin(rad) * (outHeight - y));
// if the radious value is between 1 and
if ((radius > 0) && (radius <= outWidth))
{
houghMap[radius, theta + outHeightHalf]++;
}
}
}
}
}
}
}
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
Bitmap bitmap = (Bitmap)pictureBox1.Image as Bitmap;
int[,] intImage = ToInteger(bitmap);
HoughMap houghMap = new HoughMap();
houghMap.image = intImage;
houghMap.Compute();
int[,] normalized = Rescale(houghMap.houghMap);
Bitmap hough = ToBitmap(normalized, bitmap.PixelFormat);
pictureBox2.Image = hough;
}
public static int[,] Rescale(int[,] image)
{
int[,] imageCopy = (int[,])image.Clone();
int Width = imageCopy.GetLength(0);
int Height = imageCopy.GetLength(1);
int minVal = 0;
int maxVal = 0;
for (int j = 0; j < Height; j++)
{
for (int i = 0; i < Width; i++)
{
double conv = imageCopy[i, j];
minVal = (int)Math.Min(minVal, conv);
maxVal = (int)Math.Max(maxVal, conv);
}
}
int minRange = 0;
int maxRange = 255;
int[,] array2d = new int[Width, Height];
for (int j = 0; j < Height; j++)
{
for (int i = 0; i < Width; i++)
{
array2d[i, j] = (maxRange - minRange) * (imageCopy[i,j] - minVal) / (maxVal - minVal) + minRange;
}
}
return array2d;
}
public int[,] ToInteger(Bitmap input)
{
int Width = input.Width;
int Height = input.Height;
int[,] array2d = new int[Width, Height];
for (int y = 0; y < Height; y++)
{
for (int x = 0; x < Width; x++)
{
Color cl = input.GetPixel(x, y);
int gray = (int)Convert.ChangeType(cl.R * 0.3 + cl.G * 0.59 + cl.B * 0.11, typeof(int));
array2d[x, y] = gray;
}
}
return array2d;
}
public Bitmap ToBitmap(int[,] image, PixelFormat pixelFormat)
{
int[,] imageCopy = (int[,])image.Clone();
int Width = imageCopy.GetLength(0);
int Height = imageCopy.GetLength(1);
Bitmap bitmap = new Bitmap(Width, Height, pixelFormat);
for (int y = 0; y < Height; y++)
{
for (int x = 0; x < Width; x++)
{
int iii = imageCopy[x, y];
Color clr = Color.FromArgb(iii, iii, iii);
bitmap.SetPixel(x, y, clr);
}
}
return bitmap;
}
}
I have solved the problem from this link. The source code from this link is the best one I have ever came across.
public class HoughMap
{
public int[,] houghMap { get; private set; }
public int[,] image { get; set; }
public void Compute()
{
if (image != null)
{
// get source image size
int Width = image.GetLength(0);
int Height = image.GetLength(1);
int centerX = Width / 2;
int centerY = Height / 2;
int maxTheta = 180;
int houghHeight = (int)(Math.Sqrt(2) * Math.Max(Width, Height)) / 2;
int doubleHeight = houghHeight * 2;
int houghHeightHalf = houghHeight / 2;
int houghWidthHalf = maxTheta / 2;
houghMap = new int[doubleHeight, maxTheta];
// scanning through each (x,y) pixel of the image--+
for (int y = 0; y < Height; y++) //|
{ //|
for (int x = 0; x < Width; x++)//<-------------+
{
if (image[x, y] != 0)//if a pixel is black, skip it.
{
// We are drawing some Sine waves.
// It may vary from -90 to +90 degrees.
for (int theta = 0; theta < maxTheta; theta++)
{
double rad = theta *Math.PI / 180;
// respective radius value is computed
int rho = (int)(((x - centerX) * Math.Cos(rad)) + ((y - centerY) * Math.Sin(rad)));
// get rid of negative value
rho += houghHeight;
// if the radious value is between
// 1 and twice the houghHeight
if ((rho > 0) && (rho <= doubleHeight))
{
houghMap[rho, theta]++;
}
}
}
}
}
}
}
}
Just look at this C++ code, and this C# code. So, complicated and messy that my brain got arrested. Especially, the C++ one. I never anticipated someone to store 2D values in a 1D array.
I am trying to detect light from 2 LED lights (red and blue) I did that using Bernsen thresholding technique. However, I applied that to an image. Now I want to apply that same technique but to a live video from my webcam. Is there anyway I could simply edit the code for this technique on the image to make it work on a video from the webcam? I will add below the code I used for this thresholding technique.
private ArrayList getNeighbours(int xPos, int yPos, Bitmap bitmap)
{
//This goes around the image in windows of 5
ArrayList neighboursList = new ArrayList();
int xStart, yStart, xFinish, yFinish;
int pixel;
xStart = xPos - 5;
yStart = yPos - 5;
xFinish = xPos + 5;
yFinish = yPos + 5;
for (int y = yStart; y <= yFinish; y++)
{
for (int x = xStart; x <= xFinish; x++)
{
if (x < 0 || y < 0 || x > (bitmap.Width - 1) || y > (bitmap.Height - 1))
{
continue;
}
else
{
pixel = bitmap.GetPixel(x, y).R;
neighboursList.Add(pixel);
}
}
}
return neighboursList;
}
private void button5_Click_1(object sender, EventArgs e)
{
//The input image
Bitmap image = new Bitmap(pictureBox2.Image);
progressBar1.Minimum = 0;
progressBar1.Maximum = image.Height - 1;
progressBar1.Value = 0;
Bitmap result = new Bitmap(pictureBox2.Image);
int iMin, iMax, t, c, contrastThreshold, pixel;
contrastThreshold = 180;
ArrayList list = new ArrayList();
for (int y = 0; y < image.Height; y++)
{
for (int x = 0; x < image.Width; x++)
{
list.Clear();
pixel = image.GetPixel(x, y).R;
list = getNeighbours(x, y, image);
list.Sort();
iMin = Convert.ToByte(list[0]);
iMax = Convert.ToByte(list[list.Count - 1]);
// These are the calculations to test whether the
current pixel is light or dark
t = ((iMax + iMin) / 2);
c = (iMax - iMin);
if (c < contrastThreshold)
{
pixel = ((t >= 160) ? 0 : 255);
}
else
{
pixel = ((pixel >= t) ? 0 : 255);
}
result.SetPixel(x, y, Color.FromArgb(pixel, pixel, pixel));
}
progressBar1.Value = y;
}
pictureBox3.Image =result;
}
The sharpened image becomes dark.
Why doe you think this is the case?
where to look for problems?
.
Relevant Source Code
Sharpening Code
public static Bitmap FftSharpen(Bitmap image, double[,] mask)
{
if (image.PixelFormat == PixelFormat.Format8bppIndexed)
{
Bitmap imageClone = (Bitmap)image.Clone();
double[,] maskClone = (double[,])mask.Clone();
Complex[,] cPaddedImage = ImageDataConverter.ToComplex(imageClone);
Complex[,] cPaddedMask = ImageDataConverter.ToComplex(maskClone);
Complex[,] cConvolved = Convolution.Convolve(cPaddedImage, cPaddedMask);
return ImageDataConverter.ToBitmap(cConvolved);
}
else
{
throw new Exception("not a grascale");
}
}
WinForms code
public SharpeningFilterForm()
{
InitializeComponent();
//Obtain image and kernel
Bitmap inputImage = Grayscale.ToGrayscale(Bitmap.FromFile(lenaPath) as Bitmap);
double[,] numericalKernel = new double[,] {
{ -1, -1, -1, },
{ -1, 9, -1, },
{ -1, -1, -1, },
};
//Padding operation
Bitmap inputImageCopy = (Bitmap)inputImage.Clone();
int maxWidth = (int)Math.Max(inputImageCopy.Width, numericalKernel.GetLength(0));
int maxHeight = (int)Math.Max(inputImageCopy.Height, numericalKernel.GetLength(1));
Bitmap paddedInputImage = ImagePadder.Pad(inputImageCopy, maxWidth, maxHeight);
double [,]paddedNumericalKernel = ImagePadder.Pad(numericalKernel, maxWidth, maxHeight);
//Sharpening
Bitmap sharpened = SharpenFilter.FftSharpen(paddedInputImage, paddedNumericalKernel);
//Displaying
inputImagePictureBox.Image = inputImage;
maskPictureBox.Image = ImageDataConverter.ToBitmap(numericalKernel);
paddedImagePictureBox.Image = paddedInputImage;
paddedMaskPictureBox.Image = ImageDataConverter.ToBitmap(paddedNumericalKernel);
filteredPictureBox.Image = sharpened as Image;
}
Convolution.cs
public static partial class Convolution
{
public static Complex[,] Convolve(Complex[,] image1, Complex[,] mask1)
{
Complex[,] image = (Complex[,])image1.Clone();
Complex[,] mask = (Complex[,])mask1.Clone();
Complex[,] convolve = null;
int imageWidth = image.GetLength(0);
int imageHeight = image.GetLength(1);
int maskWidth = mask.GetLength(0);
int maskeHeight = mask.GetLength(1);
if (imageWidth == maskWidth && imageHeight == maskeHeight)
{
Complex[,] ftForImage = FourierTransform.ForwardFFT(image);
Complex[,] ftForMask = FourierTransform.ForwardFFT(mask);
Complex[,] fftImage = ftForImage;
Complex[,] fftKernel = ftForMask;
Complex[,] fftConvolved = new Complex[imageWidth, imageHeight];
for (int j = 0; j < imageHeight; j++)
{
for (int i = 0; i < imageWidth; i++)
{
fftConvolved[i, j] = fftImage[i, j] * fftKernel[i, j];
}
}
Complex[,] ftForConv = FourierTransform.InverseFFT(fftConvolved);
convolve = ftForConv;
Rescale(convolve);
convolve = FourierShifter.ShiftFft(convolve);
}
else
{
throw new Exception("padding needed");
}
return convolve;
}
private static void Rescale(Complex[,] convolve)
{
int imageWidth = convolve.GetLength(0);
int imageHeight = convolve.GetLength(1);
double maxAmp = 0.0;
for (int j = 0; j < imageHeight; j++)
{
for (int i = 0; i < imageWidth; i++)
{
maxAmp = Math.Max(maxAmp, convolve[i, j].Magnitude);
}
}
double scale = 255.0 / maxAmp;
for (int j = 0; j < imageHeight; j++)
{
for (int i = 0; i < imageWidth; i++)
{
convolve[i, j] = new Complex(convolve[i, j].Real * scale, convolve[i, j].Imaginary * scale);
maxAmp = Math.Max(maxAmp, convolve[i, j].Magnitude);
}
}
}