I've tried open source projects such as this one however it doesn't seem to work at all for me. I then attempted to write my own algorithm like so (tolerance isn't being used yet).
public static Rectangle ImageSearch(Bitmap ToSearch, Bitmap ToFind, int Tolerance, double MinPercent) {
Rectangle ReturnValue = Rectangle.Empty;
BitmapData ToSearchData = ToSearch.LockBits(new Rectangle(0, 0, ToSearch.Width, ToSearch.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
BitmapData ToFindData = ToFind.LockBits(new Rectangle(0, 0, ToFind.Width, ToFind.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
IntPtr ToSearchScan0 = ToSearchData.Scan0;
IntPtr ToFindScan0 = ToFindData.Scan0;
int PixelWidth = 3; // 3 since 24 bits per pixel format
int ToSearchStride = ToSearchData.Stride;
int ToSearchPadding = ToSearchStride - (ToSearch.Width * PixelWidth);
int ToFindStride = ToFindData.Stride;
int ToFindPadding = ToFindStride - (ToFind.Width * PixelWidth);
unsafe {
byte *ToSearchPixelArray = (byte*)(void*)ToSearchData.Scan0;
byte *ToFindPixelArray = (byte*)(void*)ToFindData.Scan0;
byte sB, sG, sR, fB, fG, fR;
fB = ToFindPixelArray[0];
fG = ToFindPixelArray[1];
fR = ToFindPixelArray[2];
for (int sY = 0; sY < ToSearch.Height; sY++) {
for (int sX = 0; sX < ToSearch.Width * PixelWidth; sX += PixelWidth) {
sB = ToSearchPixelArray[0];
sG = ToSearchPixelArray[1];
sR = ToSearchPixelArray[2];
if (sB == fB && sG == fG && sR == fR) {
Console.WriteLine("found possible match");
byte *ToSearchBackup = ToSearchPixelArray;
byte *ToFindBackup = ToFindPixelArray;
int MatchedPixels = 0;
for (int fY = 0; fY < ToFind.Height; fY++) {
for (int fX = 0; fX < ToFind.Width * PixelWidth; fX += PixelWidth) {
fB = ToFindPixelArray[0];
fG = ToFindPixelArray[1];
fR = ToFindPixelArray[2];
sB = ToSearchPixelArray[0];
sG = ToSearchPixelArray[1];
sR = ToSearchPixelArray[2];
if (sB == fB && sG == fG && sR == fR) {
++MatchedPixels;
} else {
ToSearchPixelArray = ToSearchBackup;
ToFindPixelArray = ToFindBackup;
// this is the best way to break a nested loop in C#
fX = int.MaxValue;
fY = int.MaxValue;
}
}
ToSearchPixelArray += ToSearchStride - sX;
ToFindPixelArray += ToFindPadding;
}
if (MatchedPixels / (ToFind.Width * ToFind.Height) >= MinPercent) {
ReturnValue.X = (int)(sX / 3);
ReturnValue.Y = sY;
ReturnValue.Width = ToFind.Width;
ReturnValue.Height = ToFind.Height;
// this is the best way to break a nested loop in C#
sX = int.MaxValue;
sY = int.MaxValue;
}
}
}
ToSearchPixelArray += ToSearchPadding;
}
}
ToSearch.UnlockBits(ToSearchData);
ToFind.UnlockBits(ToFindData);
return ReturnValue;
}
But not even this will detect a screenshot I take of the exact image I'm searching through. Please do not suggest things such as Emgu, I'm using this in a commercial application and cannot afford to purchase a license from any GNU licensed projects (I'm not open sourcing the project either).
Serching many entries "serchingBitmap" in "sourceBitmap".
In this one I don't using unsafe code.
public static List<Point> FindBitmapsEntry(Bitmap sourceBitmap, Bitmap serchingBitmap)
{
#region Arguments check
if (sourceBitmap == null || serchingBitmap == null)
throw new ArgumentNullException();
if (sourceBitmap.PixelFormat != serchingBitmap.PixelFormat)
throw new ArgumentException("Pixel formats arn't equal");
if (sourceBitmap.Width < serchingBitmap.Width || sourceBitmap.Height < serchingBitmap.Height)
throw new ArgumentException("Size of serchingBitmap bigger then sourceBitmap");
#endregion
var pixelFormatSize = Image.GetPixelFormatSize(sourceBitmap.PixelFormat)/8;
// Copy sourceBitmap to byte array
var sourceBitmapData = sourceBitmap.LockBits(new Rectangle(0, 0, sourceBitmap.Width, sourceBitmap.Height),
ImageLockMode.ReadOnly, sourceBitmap.PixelFormat);
var sourceBitmapBytesLength = sourceBitmapData.Stride * sourceBitmap.Height;
var sourceBytes = new byte[sourceBitmapBytesLength];
Marshal.Copy(sourceBitmapData.Scan0, sourceBytes, 0, sourceBitmapBytesLength);
sourceBitmap.UnlockBits(sourceBitmapData);
// Copy serchingBitmap to byte array
var serchingBitmapData =
serchingBitmap.LockBits(new Rectangle(0, 0, serchingBitmap.Width, serchingBitmap.Height),
ImageLockMode.ReadOnly, serchingBitmap.PixelFormat);
var serchingBitmapBytesLength = serchingBitmapData.Stride * serchingBitmap.Height;
var serchingBytes = new byte[serchingBitmapBytesLength];
Marshal.Copy(serchingBitmapData.Scan0, serchingBytes, 0, serchingBitmapBytesLength);
serchingBitmap.UnlockBits(serchingBitmapData);
var pointsList = new List<Point>();
// Serching entries
// minimazing serching zone
// sourceBitmap.Height - serchingBitmap.Height + 1
for (var mainY = 0; mainY < sourceBitmap.Height - serchingBitmap.Height + 1; mainY++)
{
var sourceY = mainY * sourceBitmapData.Stride;
for (var mainX = 0; mainX < sourceBitmap.Width - serchingBitmap.Width + 1; mainX++)
{// mainY & mainX - pixel coordinates of sourceBitmap
// sourceY + sourceX = pointer in array sourceBitmap bytes
var sourceX = mainX*pixelFormatSize;
var isEqual = true;
for (var c = 0; c < pixelFormatSize; c++)
{// through the bytes in pixel
if (sourceBytes[sourceX + sourceY + c] == serchingBytes[c])
continue;
isEqual = false;
break;
}
if (!isEqual) continue;
var isStop = false;
// find fist equalation and now we go deeper)
for (var secY = 0; secY < serchingBitmap.Height; secY++)
{
var serchY = secY * serchingBitmapData.Stride;
var sourceSecY = (mainY + secY)*sourceBitmapData.Stride;
for (var secX = 0; secX < serchingBitmap.Width; secX++)
{// secX & secY - coordinates of serchingBitmap
// serchX + serchY = pointer in array serchingBitmap bytes
var serchX = secX*pixelFormatSize;
var sourceSecX = (mainX + secX)*pixelFormatSize;
for (var c = 0; c < pixelFormatSize; c++)
{// through the bytes in pixel
if (sourceBytes[sourceSecX + sourceSecY + c] == serchingBytes[serchX + serchY + c]) continue;
// not equal - abort iteration
isStop = true;
break;
}
if (isStop) break;
}
if (isStop) break;
}
if (!isStop)
{// serching bitmap is founded!!
pointsList.Add(new Point(mainX, mainY));
}
}
}
return pointsList;
}
It doesn't work accurately for me but it does give me an idea. I think the problem with this soludion is that it is looking for an exact pixel-for-pixel instance. Basically I am doing what you are doing, trying to find 1 or more occurrences of a bitmap in another but the properties may vary like brightness, contrast, size, etc. I have tired several things including Aforge.Net and Accord.Net but I can't seem to get an acceptable accuracy > 50%. Thanks for posting.
Related
I'm writing a small steganography application in C# and was able to hide text in images. However the method I used was the GetPixel/SetPixel method which was a lot slower for larger images, which I noticed after trying to hide a mp3 file in the image. After some google searches, I found out about LockBits. While the speed did improve drastically, I discovered that I was unable to extract the encrypted data (the cipher text) which was hidden in the image.
I'm not sure if the issue is with how I insert the data or when extracting it. When attempting to extract the Base64 cipher text, it would be corrupted (random symbols and characters) and throw an exception about it not being a Base64String. I ended up changing the code by following what was on the documentation for LockBits, I'll paste it below.
Merging the cipher text
public static unsafe void MergeEncryptedData(string data, Bitmap bmp, string output) {
State s = State.HIDING;
int height = bmp.Height;
int width = bmp.Width;
var bitmapData = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, bmp.PixelFormat);
byte * scan0 = (byte * ) bitmapData.Scan0;
int bytesPerPixel = 4;
int dataIndex = 0;
byte dataValue = 0;
long colorUnitIndex = 0;
int zeros = 0;
byte R, G, B;
Parallel.For(0, height, (i, loopState) = > {
byte * currentLine = scan0 + (i * bitmapData.Stride);
for (int j = 0; j < (bitmapData.Width * bytesPerPixel); j += bytesPerPixel) {
R = currentLine[i + 2];
G = currentLine[i + 1];
B = currentLine[i];
for (int n = 0; n < 3; n++) {
if (colorUnitIndex % 8 == 0) {
if (zeros == 8) {
if ((colorUnitIndex - 1) % 3 < 2) {
currentLine[i + 2] = R;
currentLine[i + 1] = G;
currentLine[i] = B;
//bmp.SetPixel(j, i, Color.FromArgb(R, G, B));
}
loopState.Stop();
}
if (dataIndex >= data.Length) {
s = State.FILL_WITH_ZEROS;
} else {
dataValue = (byte) data[dataIndex++];
}
}
switch (colorUnitIndex % 3) {
case 0:
{
if (s == State.HIDING) {
B += (byte)(dataValue % 2);
dataValue /= 2;
}
}
break;
case 1:
{
if (s == State.HIDING) {
G += (byte)(dataValue % 2);
dataValue /= 2;
}
}
break;
case 2:
{
if (s == State.HIDING) {
R += (byte)(dataValue % 2);
dataValue /= 2;
}
currentLine[i + 2] = R;
currentLine[i + 1] = G;
currentLine[i] = B;
//bmp.SetPixel(j, i, Color.FromArgb(R, G, B));
}
break;
}
colorUnitIndex++;
if (s == State.FILL_WITH_ZEROS) {
zeros++;
}
}
}
});
bmp.UnlockBits(bitmapData);
bmp.Save(output, ImageFormat.Png);
}
Extracting the cipher text
public static unsafe string ExtractData(Bitmap bmp) {
int height = bmp.Height;
int width = bmp.Width;
var bitmapData = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, bmp.PixelFormat);
byte * scan0 = (byte * ) bitmapData.Scan0.ToPointer();
int bytesPerPixel = 4;
int colorUnitIndex = 0;
int charValue = 0;
string extractedText = String.Empty;
Parallel.For(0, height, (i, loopState) = > {
byte * currentLine = scan0 + (i * bitmapData.Stride);
for (int j = 0; j < (bitmapData.Width * bytesPerPixel); j += bytesPerPixel) {
for (int n = 0; n < 3; n++) { //this particular loop feels incorrect
switch (colorUnitIndex % 3) {
case 0:
{
charValue = charValue * 2 + currentLine[i] % 2;
}
break;
case 1:
{
charValue = charValue * 2 + currentLine[i + 1] % 2;
}
break;
case 2:
{
charValue = charValue * 2 + currentLine[i + 2] % 2;
}
break;
}
colorUnitIndex++;
if (colorUnitIndex % 8 == 0) {
charValue = reverseBits(charValue);
if (charValue == 0) {
loopState.Stop();
}
char c = (char) charValue;
extractedText += c.ToString();
}
}
}
});
bmp.UnlockBits(bitmapData);
return extractedText;
}
An example of what the extracted cipher text looks like when the error is thrown:
I$I$I$I$I$I$I$I$I$I$I$I$I$I䥉II!J$$.
It should be a Base-64 String
Just for reference, I'm using a LUT PNG image to hide the data, so I'm able see a slight difference in color when compared to the original. So I know the RGB values are indeed being changed.
You need to consider:
Stride - image data with may be different of image width. More info here.
Image number of color/data channels
8 bpp (1 channel)
24 bpp (3 channels RGB)
32 bpp (4 channels ARGB, where A means alpha, transparency)
You mention RGB PNG but you are using 4 channels in your code (ARGB), double check that.
Here is a sample method that WILL obtain the same data that using the slow Bitmap GetPixel, but really fast. Based on this sample you can fix your code, as:
How to calculate bits per pixel
How to use stride properly
How to read multiple channels
Code:
/// <summary>
/// Get pixel directly from unmanaged pixel data based on the Scan0 pointer.
/// </summary>
/// <param name="bmpData">BitmapData of the Bitmap to get the pixel</param>
/// <param name="p">Pixel position</param>
/// <returns>Pixel value</returns>
public static byte[] GetPixel(BitmapData bmpData, Point p)
{
if ((p.X > bmpData.Width - 1) || (p.Y > bmpData.Height - 1))
throw new ArgumentException("GetPixel Point p is outside image bounds!");
int bitsPerPixel = ((int)bmpData.PixelFormat >> 8) & 0xFF;
int channels = bitsPerPixel / 8;
byte[] data = new byte[channels];
int id = p.Y * bmpData.Stride + p.X * channels;
unsafe
{
byte* pData = (byte*)bmpData.Scan0;
for (int i = 0; i < data.Length; i++)
{
data[i] = pData[id + i];
}
}
return data;
}
I have to calculate the spectrum values of an audio.
I used aForge's FFT in Sources/Math/FourierTransform.cs and I used an example of sampling with 16 samples as used in this video to check the results with excel (I tested the results in a spreadsheet like in the video).
FFT:
public enum Direction
{
Forward = 1,
Backward = -1
};
private const int minLength = 2;
private const int maxLength = 16384;
private const int minBits = 1;
private const int maxBits = 14;
private static int[][] reversedBits = new int[maxBits][];
private static Complex[,][] complexRotation = new Complex[maxBits, 2][];
static void Main(string[] args)
{
var Data = new Complex[16];
Data[0] = new Complex(0, 0);
Data[1] = new Complex((float)0.998027, 0);
Data[2] = new Complex((float)0.125333, 0);
Data[3] = new Complex((float)-0.98229, 0);
Data[4] = new Complex((float)-0.24869, 0);
Data[5] = new Complex((float)0.951057, 0);
Data[6] = new Complex((float)0.368125, 0);
Data[7] = new Complex((float)-0.90483, 0);
Data[8] = new Complex((float)-0.48175, 0);
Data[9] = new Complex((float)0.844328, 0);
Data[10] = new Complex((float)0.587785, 0);
Data[11] = new Complex((float)-0.77051, 0);
Data[12] = new Complex((float)-0.68455, 0);
Data[13] = new Complex((float)0.684547, 0);
Data[14] = new Complex((float)0.770513, 0);
Data[15] = new Complex((float)-0.58779, 0);
FFT(Data, Direction.Forward);
for (int a = 0; a <= Data.Length - 1; a++)
{
Console.WriteLine(Data[a].Re.ToString());
}
Console.ReadLine();
}
public static void FFT(Complex[] data, Direction direction)
{
int n = data.Length;
int m = Tools.Log2(n);
// reorder data first
ReorderData(data);
// compute FFT
int tn = 1, tm;
for (int k = 1; k <= m; k++)
{
Complex[] rotation = GetComplexRotation(k, direction);
tm = tn;
tn <<= 1;
for (int i = 0; i < tm; i++)
{
Complex t = rotation[i];
for (int even = i; even < n; even += tn)
{
int odd = even + tm;
Complex ce = data[even];
Complex co = data[odd];
double tr = co.Re * t.Re - co.Im * t.Im;
double ti = co.Re * t.Im + co.Im * t.Re;
data[even].Re += tr;
data[even].Im += ti;
data[odd].Re = ce.Re - tr;
data[odd].Im = ce.Im - ti;
}
}
}
if (direction == Direction.Forward)
{
for (int i = 0; i < n; i++)
{
data[i].Re /= (double)n;
data[i].Im /= (double)n;
}
}
}
private static int[] GetReversedBits(int numberOfBits)
{
if ((numberOfBits < minBits) || (numberOfBits > maxBits))
throw new ArgumentOutOfRangeException();
// check if the array is already calculated
if (reversedBits[numberOfBits - 1] == null)
{
int n = Tools.Pow2(numberOfBits);
int[] rBits = new int[n];
// calculate the array
for (int i = 0; i < n; i++)
{
int oldBits = i;
int newBits = 0;
for (int j = 0; j < numberOfBits; j++)
{
newBits = (newBits << 1) | (oldBits & 1);
oldBits = (oldBits >> 1);
}
rBits[i] = newBits;
}
reversedBits[numberOfBits - 1] = rBits;
}
return reversedBits[numberOfBits - 1];
}
private static Complex[] GetComplexRotation(int numberOfBits, Direction direction)
{
int directionIndex = (direction == Direction.Forward) ? 0 : 1;
// check if the array is already calculated
if (complexRotation[numberOfBits - 1, directionIndex] == null)
{
int n = 1 << (numberOfBits - 1);
double uR = 1.0;
double uI = 0.0;
double angle = System.Math.PI / n * (int)direction;
double wR = System.Math.Cos(angle);
double wI = System.Math.Sin(angle);
double t;
Complex[] rotation = new Complex[n];
for (int i = 0; i < n; i++)
{
rotation[i] = new Complex(uR, uI);
t = uR * wI + uI * wR;
uR = uR * wR - uI * wI;
uI = t;
}
complexRotation[numberOfBits - 1, directionIndex] = rotation;
}
return complexRotation[numberOfBits - 1, directionIndex];
}
// Reorder data for FFT using
private static void ReorderData(Complex[] data)
{
int len = data.Length;
// check data length
if ((len < minLength) || (len > maxLength) || (!Tools.IsPowerOf2(len)))
throw new ArgumentException("Incorrect data length.");
int[] rBits = GetReversedBits(Tools.Log2(len));
for (int i = 0; i < len; i++)
{
int s = rBits[i];
if (s > i)
{
Complex t = data[i];
data[i] = data[s];
data[s] = t;
}
}
}
These are the results after the transformation:
Output FFT results: Excel FFT results:
0,0418315622955561 0,669305
0,0533257974328085 0,716163407
0,137615673627316 0,908647001
0,114642731070279 1,673453043
0,234673940537634 7,474988602
0,0811255020953362 0,880988382
0,138088891589122 0,406276784
0,0623766891658306 0,248854492
0,0272978749126196 0,204227
0,0124250144575261 0,248854492
0,053787064184711 0,406276784
0,00783331226557493 0,880988382
0,0884368745610118 7,474988602
0,0155431246384978 1,673453043
0,0301093757152557 0,908647001
0 0,716163407
The results are not at all similar. Where is it wrong?
Is the implementation of complex (Data) wrong or is the FFT method wrong or other?
Thanks in advance!
First, the resulting FFT is a complex function in general. You're only displaying the real parts in your code but the thing you're comparing to is displaying the magnitudes, so of course they're going to be different: you're comparing apples to oranges.
When you use magnitudes and compare apples to apples, you should get this:
for (int a = 0; a <= Data.Length - 1; a++)
{
Console.WriteLine(Data[a].Magnitude.ToString());
}
...
0.0418315622955561
0.0447602132472683
0.0567904388057513
0.104590813761862
0.46718679147454
0.0550617784710375
0.025392294285886
0.0155534081359397
0.0127641875296831
0.0155534081359397
0.025392294285886
0.0550617784710375
0.46718679147454
0.104590813761862
0.0567904388057513
0.0447602132472683
That looks a little better -- it has the same symmetry property as the Excel output and there appear to be peaks in the same locations.
It almost looks like the scale is off. If I divide each element by the corresponding element from the Excel output, I get:
16
16
16
16
16
16
16
16
16
16
16
16
16
16
16
16
So your results are pretty much correct, just off by a scaling factor.
You're dividing everything by n in the last step of your FFT:
if (direction == Direction.Forward)
{
for (int i = 0; i < n; i++)
{
data[i].Re /= (double)n;
data[i].Im /= (double)n;
}
}
This is conventionally done for the inverse transform, not the forward transform.
In summary, changing the output from Data[a].Re to Data[a].Magnitude and changing the condition at the end of FFT from if (direction == Direction.Forward) to if (direction == Direction.Backward), I get this output:
0.669304996728897
0.716163411956293
0.908647020892022
1.67345302018979
7.47498866359264
0.880988455536601
0.406276708574176
0.248854530175035
0.20422700047493
0.248854530175035
0.406276708574176
0.880988455536601
7.47498866359264
1.67345302018979
0.908647020892022
0.716163411956293
which matches the Excel output.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
Tihs is a code that impliments the adaptive histogram equalization algorithm,called by a button in the c# main form, the image is about 1024*768 in size. The problem is this code is too slow ,I don't know where I should modify to improve the performance...Please give me some advice....thanks..
private void AHE_BMP_advanced(Int32 halfblocksize)
{
//adaptive histogram equalization
Size imgsz = sourceBMP.Size;
//compute total number of pixels
double totalNum = imgsz.Height * imgsz.Width;
//temp image for storation
Bitmap tempImg = new Bitmap(imgsz.Width, imgsz.Height);
//region statistics
double[,] prob = new double[256, 3];
Int32[,] mapping = new Int32[256, 3];
double[] probSum = new double[3];
for (int i = 0; i < imgsz.Height; i++)
{
for (int j = 0; j < imgsz.Width; j++)
{
//this.textBox2.Text = "i=" + i.ToString() + "j=" + j.ToString();
for (int u = 0; u < 256; u++) {
for (int v = 0; v < 3; v++) {
prob[u, v] = 0;
mapping[u, v] = 0;
}
}
//produce ahe for this pixel:
for (int u = i - halfblocksize; u <= i + halfblocksize; u++)
{
for (int v = j - halfblocksize; v <= j + halfblocksize; v++)
{
//uv->hi,wi;
int hi, wi;
hi = u;
wi = v;
//mirror:
if (hi < 0) hi = -hi;
else if (hi >= imgsz.Height)
hi = 2 * (imgsz.Height - 1) - hi;
if (wi < 0) wi = -wi;
else if (wi >= imgsz.Width)
wi = 2 * (imgsz.Width - 1) - wi;
//get hist
prob[sBmpdata[wi,hi,0], 0] += 1;
prob[sBmpdata[wi,hi,1], 1] += 1;
prob[sBmpdata[wi,hi,2], 2] += 1;
}
}
//get ahe value:
//probSum init:
probSum[0] = 0;
probSum[1] = 0;
probSum[2] = 0;
for (int k = 0; k < 256; k++)
{
this.textBox2.Text += "prob[" + k.ToString()+ ",0]=" +
prob[k,0].ToString()+"\r\n";
prob[k, 0] /= totalNum;
prob[k, 1] /= totalNum;
prob[k, 2] /= totalNum;
//Sum
probSum[0] += prob[k, 0];
probSum[1] += prob[k, 1];
probSum[2] += prob[k, 2];
if(i==40&&j==40)
//mapping(INT32)
mapping[k, 0] = Convert.ToInt32(255.0 * probSum[0]);
mapping[k, 1] = Convert.ToInt32(255.0 * probSum[1]);
mapping[k, 2] = Convert.ToInt32(255.0 * probSum[2]);
}
tempImg.SetPixel(j, i,
Color.FromArgb(mapping[sBmpdata[j,i,0], 0],
mapping[sBmpdata[j,i,1], 1], mapping[sBmpdata[j,i,2], 2]));
}
}
this.pictureBox1.Image = tempImg;
}
SetPixel
SetPixel is very slow. Look in to using LockBits. MSDN has good example.
String concatenation inside a loop
This line inside a loop is also inefficient as it creates 256 strings for each pixel, so 201 million strings allocated, that's got to be expensive!
for (int k = 0; k < 256; k++)
this.textBox2.Text += "prob[" + k.ToString()+ ",0]=" + prob[k,0].ToString()+"\r\n";
If it's debug, take it out, 201 million lines of debug text is not useful to you. It you need it you are better off writing to a file as otherwise it's going to take many GB's of ram to store the final string.
Using SetPixel is actually a fairly inefficient way of working with image data. If you want to scan across the whole image I'd suggest manipulating the image data directly using the BitmapData class.
// Create a new bitmap.
Bitmap bmp = new Bitmap("c:\\fakePhoto.jpg");
// Lock the bitmap's bits.
Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
System.Drawing.Imaging.BitmapData bmpData =
bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite,
bmp.PixelFormat);
// Get the address of the first line.
IntPtr ptr = bmpData.Scan0;
// Declare an array to hold the bytes of the bitmap.
int bytes = Math.Abs(bmpData.Stride) * bmp.Height;
byte[] rgbValues = new byte[bytes];
// Copy the RGB values into the array.
System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes);
// Set every third value to 255. A 24bpp bitmap will look red.
for (int counter = 2; counter < rgbValues.Length; counter += 3)
rgbValues[counter] = 255;
// Copy the RGB values back to the bitmap
System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, ptr, bytes);
// Unlock the bits.
bmp.UnlockBits(bmpData);
// Draw the modified image.
e.Graphics.DrawImage(bmp, 0, 150);
Well, I think you should write
private void AHE_BMP_advanced(Int32 halfblocksize)
{
this.pictureBox1.Image = GetAHE_BMP_advanced(halfblocksize, sourceBMP.Size, sBmpdata);
}
where GetAHE_BMP_advanced is
private static Bitmap GetAHE_BMP_advanced(int halfblocksize, Size sourceBmpSize, int[,,] sourceBmpData)
{
const int m = 256;
const int n = 3;
//adaptive histogram equalization
Size imgsz = sourceBmpSize;
//compute total number of pixels
double totalNum = imgsz.Height * imgsz.Width;
var colors = new Color[sourceBmpSize.Width, sourceBmpSize.Height];
for (int i = 0; i < imgsz.Height; i++)
{
for (int j = 0; j < imgsz.Width; j++)
{
double[,] prob = new double[m, n];
int[,] mapping = new int[m, n];
//produce ahe for this pixel:
for (int u = i - halfblocksize; u <= i + halfblocksize; u++)
{
for (int v = j - halfblocksize; v <= j + halfblocksize; v++)
{
int hi = u;
int wi = v;
//mirror:
if (hi < 0) hi = -hi;
else if (hi >= imgsz.Height)
hi = 2 * (imgsz.Height - 1) - hi;
if (wi < 0) wi = -wi;
else if (wi >= imgsz.Width)
wi = 2 * (imgsz.Width - 1) - wi;
//get hist
prob[sourceBmpData[wi, hi, 0], 0] += 1;
prob[sourceBmpData[wi, hi, 1], 1] += 1;
prob[sourceBmpData[wi, hi, 2], 2] += 1;
}
}
double[] probSum = new double[n];
for (int k = 0; k < m; k++)
{
prob[k, 0] /= totalNum;
prob[k, 1] /= totalNum;
prob[k, 2] /= totalNum;
//Sum
probSum[0] += prob[k, 0];
probSum[1] += prob[k, 1];
probSum[2] += prob[k, 2];
if (i == 40 && j == 40) //mapping(INT32)
{
mapping[k, 0] = Convert.ToInt32(255.0 * probSum[0]);
mapping[k, 1] = Convert.ToInt32(255.0 * probSum[1]);
mapping[k, 2] = Convert.ToInt32(255.0 * probSum[2]);
}
}
colors[i, j] = Color.FromArgb(mapping[sourceBmpData[j, i, 0], 0],
mapping[sourceBmpData[j, i, 1], 1],
mapping[sourceBmpData[j, i, 2], 2]);
}
}
return BitmapHelper.CreateBitmap(colors);
}
where BitmapHelper is:
public static class BitmapHelper
{
public struct Pixel : IEquatable
{
// ReSharper disable UnassignedField.Compiler
public byte Blue;
public byte Green;
public byte Red;
public bool Equals(Pixel other)
{
return Red == other.Red && Green == other.Green && Blue == other.Blue;
}
}
public static Color[,] GetPixels(Bitmap two)
{
return ProcessBitmap(two, pixel => Color.FromArgb(pixel.Red, pixel.Green, pixel.Blue));
}
public static float[,] GetBrightness(Bitmap two)
{
return ProcessBitmap(two, pixel => Color.FromArgb(pixel.Red, pixel.Green, pixel.Blue).GetBrightness());
}
public static unsafe T[,] ProcessBitmap<T>(Bitmap bitmap, Func<Pixel, T> func)
{
var lockBits = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly,
bitmap.PixelFormat);
int padding = lockBits.Stride - (bitmap.Width * sizeof(Pixel));
int width = bitmap.Width;
int height = bitmap.Height;
var result = new T[height, width];
var ptr = (byte*)lockBits.Scan0;
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
var pixel = (Pixel*)ptr;
result[i, j] = func(*pixel);
ptr += sizeof(Pixel);
}
ptr += padding;
}
bitmap.UnlockBits(lockBits);
return result;
}
public static Bitmap CreateBitmap(Color[,] colors)
{
const int bytesPerPixel = 4, stride = 8;
int width = colors.GetLength(0);
int height = colors.GetLength(1);
byte[] bytes = new byte[width*height*bytesPerPixel];
int n = 0;
for (int i = 0; i < width; i++)
{
for (int j = 0; j < height; j++)
{
bytes[n++] = colors[i, j].R;
bytes[n++] = colors[i, j].G;
bytes[n++] = colors[i, j].B;
bytes[n++] = colors[i, j].A;
}
}
return CreateBitmap(bytes, width, height, stride, PixelFormat.Format32bppArgb);
}
public static Bitmap CreateBitmap(byte[] data, int width, int height, int stride, PixelFormat format)
{
var arrayHandle = GCHandle.Alloc(data, GCHandleType.Pinned);
var bmp = new Bitmap(width, height, stride, format, arrayHandle.AddrOfPinnedObject());
arrayHandle.Free();
return bmp;
}
}
hi i'm using visual studio 2008 and c++ to implement the watershed algorithm it works well.But i'm recently working on converting the same code into c# using opencvsharp wrapper class in visual studio 2010.I completed most of the code but i couldn't convert uchar ptr into opencvsharp i even use byte data type but it doesn't work.
here is the link to the c++ source code
code.ros.org/trac/opencv/browser/trunk/opencv/samples/c/watershed.cpp?rev=493
and this is where i get the trouble
uchar* ptr = color_tab->data.ptr + i*3;
ptr[0] = (uchar)(cvRandInt(&rng)%180 + 50);
ptr[1] = (uchar)(cvRandInt(&rng)%180 + 50);
ptr[2] = (uchar)(cvRandInt(&rng)%180 + 50);
any help will be appreciated. thank you.
here is the c# code I've been working on, i cant complete the code any help
using (IplImage img0 = new IplImage("1180.jpg", LoadMode.AnyDepth | LoadMode.AnyColor)){
using (IplImage img = img0.Clone())
using (IplImage marker_mask = new IplImage(img0.Size, BitDepth.U8, 1))
using (IplImage markers = new IplImage(img.Size, BitDepth.S32, 1))
using (IplImage img_gray = img0.Clone())
using (IplImage wshed = img0.Clone()){
wshed.Zero();
marker_mask.Zero();
using (CvWindow w_image = new CvWindow("image", WindowMode.AutoSize, img))
{
CvPoint prev_pt = new CvPoint(-1, -1);
w_image.OnMouseCallback += delegate(MouseEvent ev, int x, int y, MouseEvent flags)
{
if (ev == MouseEvent.LButtonUp || (flags & MouseEvent.FlagLButton) == 0)
{
prev_pt = new CvPoint(-1, -1);
}
else if (ev == MouseEvent.LButtonDown)
{
prev_pt = new CvPoint(x, y);
}
else if (ev == MouseEvent.MouseMove && (flags & MouseEvent.FlagLButton) != 0)
{
CvPoint pt = new CvPoint(x, y);
if (prev_pt.X < 0)
{
prev_pt = pt;
}
marker_mask.Line(prev_pt,pt,Cv.ScalarAll(255),5,LineType.Link8,0);
img.Line(prev_pt,pt,Cv.ScalarAll(255),5,LineType.Link8,0);
prev_pt = pt;
w_image.ShowImage(img);
}
};
for (; ; )
{
switch (CvWindow.WaitKey(0))
{
case 27:
return;
case 'r':
marker_mask.Zero();
img0.Copy(img);
w_image.ShowImage(img);
break;
case 'w':
case '\r':
CvSeq<CvPoint> contours;
CvMat color_tab=null;
int i,j,comp_count=0;
CvMemStorage storage = new CvMemStorage();
Cv.FindContours(marker_mask,storage, out contours);
markers.Zero();
for(; contours !=null; contours=contours.HNext,comp_count++){
Cv.DrawContours(markers, contours, Cv.ScalarAll(comp_count+1), Cv.ScalarAll(comp_count+1),-1,-1,LineType.Link8,new CvPoint(0,0));
}
if(comp_count ==0){
continue;
color_tab=Cv.CreateMat(1,comp_count,MatrixType.U8C3);
for(i=0;i<comp_count;i++){
/*
uchar* ptr = color_tab->data.ptr + i*3;
ptr[0] = (uchar)(cvRandInt(&rng)%180 + 50);
ptr[1] = (uchar)(cvRandInt(&rng)%180 + 50);
ptr[2] = (uchar)(cvRandInt(&rng)%180 + 50);
*/
}
{
double t =(double)Cv.GetTickCount();
Cv.Watershed(img0,markers);
Cv.Save(markers,"img0.xml");
t=(double)Cv.GetTickCount()-t;
Console.WriteLine("exec time = %gms\n",t/(Cv.GetTickFrequency()*1000));
}
// paint the watershed image
for(i=0;i<markers.Height;i++)
for(j=0;i<markers.Width;j++)
{
int idx =
}
Cv.AddWeighted(wshed,0.5,img_gray,0.5,0,wshed);
Cv.ShowImage("watershed transform",wshed);
Cv.ReleaseMat(color_tab);
}
}
return 0;
}
}
}
thanks torak but seems it doesn't work i modified the c# code like this
unsafe{
CvRNG rng = new CvRNG();
byte* ptr = (byte*)color_tab.Data.ptr +i*3;
ptr[0] = (byte)(Cv.RandInt(rng)%180 + 50);
ptr[1] = (byte)(Cv.RandInt(rng)%180 + 50);
ptr[2] = (byte)(Cv.RandInt(rng)%180 + 50);
}
It doesn't give any error but i'm not sure about the out put i got a new problem now.I can't convert macro CV_IMAGE_ELEM() in the c++ code into c#.Can anyone help.Thanks for your comments
This is where i get the trouble in c++ code.full c++ code displayed at the beginning of the question
// paint the watershed image
for( i = 0; i < markers->height; i++ )
for( j = 0; j < markers->width; j++ )
{
int idx = CV_IMAGE_ELEM( markers, int, i, j );//markersIPL_DEPTH_32S
uchar* dst = &CV_IMAGE_ELEM( wshed, uchar, i, j*3 );//BGR,j*3
if( idx == -1 ) //-1?
dst[0] = dst[1] = dst[2] = (uchar)255;
else if( idx <= 0 || idx > comp_count ) //
dst[0] = dst[1] = dst[2] = (uchar)0; // should not get here
else //
{
uchar* ptr = color_tab->data.ptr + (idx-1)*3;
dst[0] = ptr[0]; dst[1] = ptr[1]; dst[2] = ptr[2];
}
}
After a quick look, it seems that the way you the data is using the appropriate DataArray... member of color_tab. In your case that would be color_tab.DataArrayByte[...] producing something like:
for (i = 0; i < comp_count * 3; i++)
ptr[i] = (byte)(cvRandInt(...) % 180 + 50);
I haven't looked at the random number generation, and hence I can't test it at the moment, but I suspect it addresses your issue. Fingers crossed.
This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
I have designed a forms app which could have been better designed for unit testing by using business logic etc but at this stage I do not want to alter my code. It is an app which performs steganography whereby a message is embedded in an image using an LSB algorithm. I am currently trying to write a unit test for the button2 click event. When button2 is pressed; it will take text from two other textboxes and an image from a picturebox and run the LSB algorithm. Below is the test function. I create test values for the textboxes concerned. When I run the test I get: System.NullReferenceException: Object reference not set to an instance of an object. Does this refer to the object sender = null; EventArgs e = null;. Or is what I am doing even possible? Do I have to resort to NUnitForms? I have added button2_click after the test function:
public void button2_ClickTest()
{
StegApp_Accessor target = new StegApp_Accessor();
// TODO: Initialize to an appropriate value
object sender = null; // TODO: Initialize to an appropriate value
EventArgs e = null; // TODO: Initialize to an appropriate value
target.textBox4.Text = "123456";
target.textBox5.Text = "test message";
target.button2_Click(sender, e);
//Assert.Inconclusive("A method that does not return a value cannot
// be verified.");
//target.textBox4.Text = "123456";
//target.textBox5.Text = "test message";
/*
if (target.textBox4.Text.Length > 6 || target.textBox4.Text.Length < 0)
{
Assert.Fail("Key is out of range");
}*/
//Assert.IsInstanceOfType(target.b1,typeof(byte[]));
if(target.b1.Length != target.temp4.Length)
{
Assert.Fail("B1 array does not have the correct lenght");
}
Assert.IsInstanceOfType(target.image1,typeof(Bitmap));
Assert.IsInstanceOfType(target.sb,typeof(StringBuilder));
if(target.sb.Length != target.tmp3.Length)
{
Assert.Fail("Issue with Stringbuilder sb. Lenght not equal to 'tmp3'!");
}
Assert.Equals(target.z,target.StringLenght);
Assert.Equals(target.c, target.textBox5.Text.Length);
}
`private void button2_Click(object sender, EventArgs e)
{
//int x1, y1, z = 0;
try
{
// Convert String Into Byte Array
//byte[] sourceData = System.Text.ASCIIEncoding.ASCII.GetBytes(a);
// Convert Each Byte Into A Binary String
//foreach (byte thisByte in sourceData)
// binaryString.Append(Convert.ToString(thisByte, 2));
while (!key)
{
if (textBox4.Text == "")
{
//b1 = ASCIIEncoding.ASCII.GetBytes(textBox5.Text);
key = false;
MessageBox.Show("Error, enter your six digit key!");
return;
}
else if (textBox4.Text.Length > 6)
{
MessageBox.Show("Error, Key too long, try again!");
return;
}
else
{
//temp4 = textBox4.Text[0] + textBox4.Text[1] + textBox4.Text[2] + textBox4.Text[3] + textBox4.Text[4] + textBox4.Text[5] + textBox5.Text;
c = textBox5.Text.Length;
temp5 = c.ToString();
if (c <= 9)
{
temp5 = "000" + temp5;
}
else if (c <= 99)
{
temp5 = "00" + temp5;
}
else if (c <= 999)
{
temp5 = "0" + temp5;
}
else if (c <= 9999)
{
}
else
{
MessageBox.Show("Message too long for this tool,try again");
return;
}
temp4 = textBox4.Text + temp5 + textBox5.Text;
b1 = ASCIIEncoding.ASCII.GetBytes(temp4);
key = true;
}
}
//byte[] b1 = ASCIIEncoding.ASCII.GetBytes(textBox5.Text);
//b1 = Encoding.Unicode.GetBytes(a);
//Create the array to be returned.
tmp2 = new string[b1.Length];
//Interate through each byte
for (int i = 0; i < b1.Length; i++)
{
int x = b1[i];
tmp = "";
while (true)
{
if ((x % 2) == 1)
{
tmp = "1" + tmp;
}
else
{
tmp = "0" + tmp;
}
x /= 2;
if (x < 1) break;
}
//Make sure the value is 8 chars long.
tmp2[i] = tmp.PadLeft(8, '0');
}
//string a="";
for (int i = 0; i < b1.Length; i++)
{
//a = tmp2[i];
tmp3 = tmp3 + tmp2[i];
}
if (key)
{
tmp3 = "00" + tmp3;
}
else
{
tmp3 = "10" + tmp3;
}
sb.Append(tmp3);
//temp5 = c.ToString();
//z= c+1;
StringLenght = sb.Length;
byte Mask0 = 254;
byte Mask1 = 1;
byte NewRed = 0, NewGreen = 0, NewBlue = 0;
// Loop through the images pixels to reset color.
for (x1 = 0, y1 = 0; x1 < image1.Width && z < StringLenght; x1++)
{
for (y1 = 0; y1 < image1.Height && z < StringLenght; y1++)
{
Color pixelColor = image1.GetPixel(x1, y1);
//byte NewRed, NewGreen, NewBlue;
if (sb[z] == '0')
{
NewRed = Convert.ToByte(pixelColor.R & Mask0);
Color newColor = Color.FromArgb(NewRed, pixelColor.G, pixelColor.B);
image1.SetPixel(x1, y1, newColor);
pixelColor = image1.GetPixel(x1, y1);
z++;
if (z == StringLenght)
{
break;
}
}
else
{
NewRed = Convert.ToByte(pixelColor.R | Mask1);
Color newColor = Color.FromArgb(NewRed, pixelColor.G, pixelColor.B);
image1.SetPixel(x1, y1, newColor);
pixelColor = image1.GetPixel(x1, y1);
z++;
if (z == StringLenght)
{
break;
}
}
if (sb[z] == '0')
{
NewGreen = Convert.ToByte(pixelColor.G & Mask0);
Color newColor = Color.FromArgb(pixelColor.R, NewGreen, pixelColor.B);
image1.SetPixel(x1, y1, newColor);
pixelColor = image1.GetPixel(x1, y1);
z++;
if (z == StringLenght)
{
break;
}
}
else
{
NewGreen = Convert.ToByte(pixelColor.G | Mask1);
Color newColor = Color.FromArgb(pixelColor.R, NewGreen, pixelColor.B);
image1.SetPixel(x1, y1, newColor);
pixelColor = image1.GetPixel(x1, y1);
z++;
if (z == StringLenght)
{
break;
}
}
if (sb[z] == '0')
{
NewBlue = Convert.ToByte(pixelColor.B & Mask0);
Color newColor = Color.FromArgb(pixelColor.R, pixelColor.G, NewBlue);
image1.SetPixel(x1, y1, newColor);
pixelColor = image1.GetPixel(x1, y1);
z++;
if (z == StringLenght)
{
break;
}
}
else
{
NewBlue = Convert.ToByte(pixelColor.B | Mask1);
Color newColor = Color.FromArgb(pixelColor.R, pixelColor.G, NewBlue);
image1.SetPixel(x1, y1, newColor);
pixelColor = image1.GetPixel(x1, y1);
z++;
if (z == StringLenght)
{
break;
}
}
//string binary1 = Convert.ToString(pixelColor.R, 2);
//char last1 = binary1[binary1.Length - 1];
}
}
MessageBox.Show("Message embedded");
//Color newColor = Color.FromArgb(NewRed, NewGreen, NewBlue);
//image1.SetPixel(x, y, newColor);
// Set the PictureBox to display the image.
//pictureBox1.Image = image1;
// Display the pixel format in Label1.
//label1.Text = "Pixel format: " + image1.PixelFormat.ToString();
}
catch (ArgumentException)
{
MessageBox.Show("There was an error." +
"Check the path to the image file.");
}
//pictureBox2.Image = image1;
//Byte[] buf = Encoding.Unicode.GetBytes(RetreivedMessage.ToString());
//Byte[] buf = Encoding.Unicode.GetBytes(RetreivedMessage.ToString());
//string result = System.Text.Encoding.Unicode.GetString(buf);
//String result = Encoding.Unicode.GetString(buf);
//StringBuilder r2 = new StringBuilder();
//foreach (Byte b in Encoding.Unicode.GetBytes(FinalRetreivedMessage))
//{
// r2.Append(Convert.ToString(b));
// }
//int v = 0;
//for (int i = 0; i < FinalRetreivedMessage.Length; i++)
// {
// v = v * 2 + (FinalRetreivedMessage[i] == '0' ? 0 : 1);
// }
//string result = v.ToString();
// copy the string as UTF-8 bytes.
// byte[] utf8Bytes = new byte[FinalRetreivedMessage.Length];
// for (int i = 0; i < FinalRetreivedMessage.Length; ++i)
// {
//Debug.Assert( 0 <= utf8String[i] && utf8String[i] <= 255, "the char must be in byte's range");
// utf8Bytes[i] = (byte)FinalRetreivedMessage[i];
// }
//Encoding.UTF8.GetString(utf8Bytes, 0, utf8Bytes.Length);
// utf8Bytes = new byte[]{1,1,1,0,1,0,0,0};
// string result1 = Encoding.UTF8.GetString(utf8Bytes, 0, utf8Bytes.Length);
//string result1 = Encoding.UTF8.GetString(utf8Bytes);
// UTF8Encoding enc = new UTF8Encoding();
// string str = enc.GetString(utf8Bytes);
// Byte[] encodedBytes = enc.GetBytes(FinalRetreivedMessage);
// string message = encodedBytes.ToString();
// int count = FinalRetreivedMessage.Length / 8;
// var bollox = new byte[count];
// for (int i = 0; i < count; i++)
// bollox[i] = Convert.ToByte(FinalRetreivedMessage.Substring(i * 8, 8), 2);
// var bollox1 = new byte[count];
//for (int i = 0; i < count; i++)
//bollox1[i] = Encoding.Unicode.GetBytes(FinalRetreivedMessage.Substring(i * 8, 8));
// string result2 = bollox.ToString();
// string result3 = enc.GetString(bollox);
// string result4 = System.Convert.ToString(bollox);
// string StringIWant = BitConverter.ToString(bollox);
// string result5 = BitConverter.ToString(encodedBytes);
// string result6 = BitConverter.ToString(utf8Bytes);
// string result7 = BitConverter.ToString(Encoding.Unicode.GetBytes(FinalRetreivedMessage));
// string result8 = System.Convert.ToString(Encoding.Unicode.GetBytes(FinalRetreivedMessage));
// string result9 = Encoding.Unicode.GetString(Encoding.Unicode.GetBytes(FinalRetreivedMessage));
// string result10 = Encoding.Default.GetString(Encoding.Unicode.GetBytes(FinalRetreivedMessage));
}`
private void button2_Click(object sender, EventArgs e)
{
Embed();
}
public void Embed(string Embedkey, string EmbedMessage,Bitmap image3)
{
// embed message in image
}
public void EmbedTest()
{
StegApp target = new StegApp(); // TODO: Initialize to an appropriate value
string Embedkey = "123456"; // TODO: Initialize to an appropriate value
string EmbedMessage = "test2"; // TODO: Initialize to an appropriate value
Bitmap image3 = null; // TODO: Initialize to an appropriate value
image3 = new Bitmap(#"C:\Users\Admin\Documents\dt265\Project\Sky\sky-and-cloud.bmp",true);
string a="123456",b="test2";
target.Embed(Embedkey, EmbedMessage, image3);
//Assert.Inconclusive("A method that does not return a value cannot be verified.");
if (Embedkey.Length > 6 || Embedkey.Length < 0)
{
Assert.Fail("Key is out of range");
}
//Assert.IsInstanceOfType(target.b1,typeof(byte[]));
if(target.b1.Length != target.temp4.Length)
{
Assert.Fail("B1 array does not have the correct lenght");
}
Assert.IsInstanceOfType(target.image1,typeof(Bitmap));
Assert.IsInstanceOfType(target.sb,typeof(StringBuilder));
if(target.sb.Length != target.tmp3.Length)
{
Assert.Fail("Issue with Stringbuilder sb. Lenght not equal to 'tmp3'!");
}
if(target.z != target.StringLenght)
{
Assert.Fail("z != StringLenght");
}
if (target.c != EmbedMessage.Length)
{
Assert.Fail("c is not the lenght of the Message!");
}
}