Valid Ways of Comparing Bitmaps - c#

I've been trying to find a way to do a quick and easy comparison between two Bitmaps and I've come up with two methods:
private static Bitmap Resize(Bitmap b, int nWidth, int nHeight)
{
Bitmap result = new Bitmap(nWidth, nHeight);
using (Graphics g = Graphics.FromImage((Image)result))
{
g.InterpolationMode = InterpolationMode.NearestNeighbor;
g.DrawImage(b, 0, 0, nWidth, nHeight);
}
return result;
}
public static Decimal CompareImages(Bitmap b1, Bitmap b2, int Approx = 64)
{
Bitmap i1 = Resize(b1, Approx, Approx);
Bitmap i2 = Resize(b2, Approx, Approx);
int diff = 0;
for (int row = 1; row < Approx; row++)
{
for (int col = 1; col < Approx; col++)
{
if (i1.GetPixel(col, row) != i2.GetPixel(col, row))
diff++;
}
}
i1.Dispose();
i2.Dispose();
return Math.Round((Decimal)(diff / (Approx ^ 2)), 2);
}
public static Decimal CompareImagesExact(Bitmap b1, Bitmap b2)
{
int h = b1.Height > b2.Height ? b1.Height : b2.Height;
int w = b1.Width > b2.Width ? b1.Width : b2.Width;
int diff = 0;
for (int row = 1; row < h; row++)
{
for (int col = 1; col < w; col++)
{
if (b1.GetPixel(col, row) != b2.GetPixel(col, row))
diff++;
}
}
return Math.Round((Decimal)(diff / ((h * w) ^ 2)), 2);
}
What I'm asking are if these are valid ways to compare Bitmaps? Are there any problems I could face when using these? And are there any more efficient ways of doing this?

Related

ActionViolation when using LockBits

I am trying to get the pixels a bit faster than one could when using .GetPixel() but I have found myself that it throws an exception with a 0,0 index with the right LockImageMode.
Exception
Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
public async Task<IList<Color>> GetColorStream( )
{
(_Width, _Height, PixelFormat pixelFormat) = await GetDimensions(_Path);
List<Color> pixels = new();
if (pixelFormat is not PixelFormat.Format32bppRgb or not PixelFormat.Format24bppRgb or not PixelFormat.Format32bppRgb)
throw new InvalidOperationException("Cant operate with ess than 24bpps");
_Data = await GetBitmapData(_Width, _Height, pixelFormat, ImageLockMode.ReadWrite);
if(pixelFormat is PixelFormat.Format24bppRgb or PixelFormat.Format32bppRgb)
{
for (int i = 0; i < _Width; i++)
for (int j = 0; j < _Height; j++)
{
int stride = i * _Data.Stride / 3 + j;
(byte R, byte G, byte B, byte A) = (Marshal.ReadByte(_Data.Scan0, stride), Marshal.ReadByte(_Data.Scan0, stride + 1),
Marshal.ReadByte(_Data.Scan0, stride + 2), 0);
pixels.Add(new Color(R, G, B, A));
}
}
else if(pixelFormat == PixelFormat.Format32bppArgb )
{
for (int i = 0; i < _Width; i++)
for (int j = 0; j < _Height; j++)
{
int stride = i * _Data.Stride / 4 + j;
(byte R, byte G, byte B, byte A) = (Marshal.ReadByte(_Data.Scan0, stride), Marshal.ReadByte(_Data.Scan0, stride + 1),
Marshal.ReadByte(_Data.Scan0, stride + 2), Marshal.ReadByte(_Data.Scan0, stride + 3));
pixels.Add(new Color(R, G, B, A));
}
}
image.UnlockBits(_Data);
image = null;
return pixels;
}```

Translating a C++ (dealing with corona) function into C#

i had a C++ .exe i was using as a standalone image cleaner.
But i now want to use its fonction into my own c# app, so i started to translate it. But i REALLY TOTALLY know nothing about C++ and its logic.
So i come here for some help.
First, does anyone know any equivalent for this function?
Corona "getPixels()" (yes with an "s" because i know c# have a built-in getPixel) :
here is the function explaination from corona doc : getPixels() Corona dll
it is used in the lines i am looking to translate.
here is all the thing:
original C++ code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "corona.h"
#define IMAGE_FORMAT corona::PF_R8G8B8 /* RGB mode - 8 bits each */
#define GetXY(x,y, w) ((x) + ((w) * (y)))
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define SQ(a) ((a) * (a))
#define DISTANCE(a, b, c, d) (SQ(a - c) + SQ(b - d))
int main(int argc, char **argv)
{
corona::Image *img;
unsigned char *pixels;
int threshold = 0;
int distance = 0;
int pixel;
char str[255];
int rows, cols;
int row, col;
unsigned char *bitmap, *p;
unsigned char *outmap;
pixels = (unsigned char*)img->getPixels();
rows = img->getHeight();
cols = img->getWidth();
bitmap = new unsigned char[rows * cols];
p = bitmap;
outmap = new unsigned char[rows * cols];
//convert to single byte grayscale
for (row = 0; row < rows; row++)
for (col = 0; col < cols; col++)
{
pixel = *pixels++;
pixel += *pixels++;
pixel += *pixels++;
*p++ = pixel / 3;
}
//free corona loading
delete img;
int distance = 8;
int threshold = 7;
//check our threshold
for (row = 0; row < rows; row++)
for (col = 0; col < cols; col++)
{
if (bitmap[GetXY(col, row, cols)])
{
int count = 0;
int x, y;
int dhalf = distance / 2 + 1;
//optimization possible here by checking inside a circle rather than square+dist
for (x = MAX(col - dhalf, 0); x < MIN(col + dhalf, cols); x++)
for (y = MAX(row - dhalf, 0); y < MIN(row + dhalf, rows); y++)
{
if (SQ(distance) > DISTANCE(col, row, x, y) && bitmap[GetXY(x, y, cols)])
count++;
}
if (count >= threshold)
outmap[GetXY(col, row, cols)] = 255;
else
outmap[GetXY(col, row, cols)] = 0;
}
else
outmap[GetXY(col, row, cols)] = 0;
}
}
What i have now with what i could translate... i hope correctly at least...:
private Bitmap optIm2(Bitmap _img)
{
int rows = _img.Height;
int cols = _img.Width;
pixels = (unsigned char)img->getPixels(); //here i dont know at all
bitmap = new unsigned char[rows * cols]; //here i dont know at all
p = bitmap;
outmap = new unsigned char[rows * cols]; //here i dont know at all
//convert to single byte grayscale
for (int row = 0; row < rows; row++)
{
for (int col = 0; col < cols; col++)
{
pixel = *pixels++; //here i dont know at all
pixel += *pixels++; //here i dont know at all
pixel += *pixels++; //here i dont know at all
*p++ = pixel / 3; //here i dont know at all
}
}
//free corona loading
delete img;
int distance = 9;
int threshold = 7;
//check our threshold
for (int row = 0; row < rows; row++)
{
for (int col = 0; col < cols; col++)
{
if (bitmap[GetXY(col, row, cols)])
{
int count = 0;
int x, y;
int dhalf = distance / 2 + 1;
//optimization possible here by checking inside a circle rather than square+dist
for (x = Math.Max(col - dhalf, 0); x < Math.Min(col + dhalf, cols); x++)
{
for (y = Math.Max(row - dhalf, 0); y < Math.Min(row + dhalf, rows); y++)
{
if (SQ(distance) > DISTANCE(col, row, x, y) && bitmap[GetXY(x, y, cols)])
count++;
}
}
if (count >= threshold)
{
outmap[GetXY(col, row, cols)] = 255;
}
else
{
outmap[GetXY(col, row, cols)] = 0;
}
}
else
{
outmap[GetXY(col, row, cols)] = 0;
}
}
}
return iDontKnowWhatYet;
}
private int GetXY(int x,int y, int w) { return ((x) + ((w) * (y))); }
private int SQ(int a) { return ((a) * (a)); }
private int DISTANCE(int a, int b, int c, int d) { return (SQ(a - c) + SQ(b - d)); }
Could anyone help me understand and convert this please?
The C# code will look something like this
private unsafe Bitmap optIm2(Bitmap img)
{
int rows = img.Height;
int cols = img.Width;
var dstImg = new Bitmap(cols, rows, img.PixelFormat);
var srcImageData = img.LockBits(new Rectangle(0, 0, cols, rows), System.Drawing.Imaging.ImageLockMode.ReadOnly, img.PixelFormat);
var dstImageData = dstImg.LockBits(new Rectangle(0, 0, cols, rows), System.Drawing.Imaging.ImageLockMode.ReadOnly, dstImg.PixelFormat);
try
{
var bitmap = new byte[rows * cols];
var outmap = new byte[rows * cols];
fixed (byte* ptr = &bitmap[0])
{
byte* pixels = (byte*)srcImageData.Scan0;
byte* p = ptr;
//convert to single byte grayscale
for (int row = 0; row < rows; row++)
{
for (int col = 0; col < cols; col++)
{
var pixel = *pixels++;
pixel += *pixels++;
pixel += *pixels++;
*p++ = (byte)(pixel / 3); //here i dont know at all
}
}
}
int distance = 9;
int threshold = 7;
//check our threshold
for (int row = 0; row < rows; row++)
{
for (int col = 0; col < cols; col++)
{
if (bitmap[GetXY(col, row, cols)] != 0)
{
int count = 0;
int x, y;
int dhalf = distance / 2 + 1;
//optimization possible here by checking inside a circle rather than square+dist
for (x = Math.Max(col - dhalf, 0); x < Math.Min(col + dhalf, cols); x++)
{
for (y = Math.Max(row - dhalf, 0); y < Math.Min(row + dhalf, rows); y++)
if ((SQ(distance) > DISTANCE(col, row, x, y)) && (bitmap[GetXY(x, y, cols)] != 0))
count++;
}
if (count >= threshold)
outmap[GetXY(col, row, cols)] = 255;
else
outmap[GetXY(col, row, cols)] = 0;
}
else
outmap[GetXY(col, row, cols)] = 0;
}
}
// Copy data from outmap to pixels of bitmap. Since outmap is grayscale data, we replicate it for all channels
byte* dstPtr = (byte*)dstImageData.Scan0;
for (int row = 0; row < rows; row++)
{
byte* rowPtr = dstPtr;
for (int col = 0; col < cols; col++)
{
*rowPtr++ = outmap[GetXY(col, row, cols)];
*rowPtr++ = outmap[GetXY(col, row, cols)];
*rowPtr++ = outmap[GetXY(col, row, cols)];
}
dstPtr += dstImageData.Stride;
}
}
finally
{
img.UnlockBits(srcImageData);
img.Dispose();
dstImg.UnlockBits(dstImageData);
}
return dstImg;
}
private int GetXY(int x, int y, int w) { return ((x) + ((w) * (y))); }
private int SQ(int a) { return ((a) * (a)); }
private int DISTANCE(int a, int b, int c, int d) { return (SQ(a - c) + SQ(b - d)); }
While I haven't checked your actual logic for the correct algorithm, the code above contains all the bits you need to do that yourself. The main points to note are:
How to get a pointer from an IntPtr (fixed)
How to get pixel data from a bitmap
How to write pixel data back to a bitmap
Hope this helps!

why is my c# code so slow [closed]

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;
}
}

index outside bounds of the array adaptive median

I'm trying to output a new image after applying the adaptive median filter but it only works if the maximum window size is 3*3, but it should work for all odd window sizes, and it does so if the image is so small for example 10*10 pixels, but if the image is for example 440*445 pixels it only works if the max window size is 3*3 otherwise it says index outside bounds of the array, here is my code using counting sort to sort the pixels:
using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
namespace ImageFilters
{
public class Class2
{
public byte[,] median(byte[,] array, int width, int height, int msize)
{
byte[,] marr = new byte[height + 1, width + 1];
int size = 3;
for (int i = 0; i <height+1; i++)
{
marr[i, 0] = 255;
}
for (int j = 0; j < width+1; j++)
{
marr[0, j] = 255;
}
int n=0;
int z=0;
for (int k = 0; k < (height) * width; k++)
{
repeat:
byte[] farr = new byte[size * size];
int I=0;
for (int i = n; i < n+size; i++)
{
for (int j = z; j < z+size; j++)
{
if (j < width && i < height)
{
farr[I] = array[i, j];
I++;
}
else
{
farr[I] = 0;
I++;
}
}
}
int zxy = farr[(size*size)/2];
byte[] check = new byte[size * size];
check=counting(farr,size);
int median = 0;
int lennn;
lennn = check.Length;
int min = 99999;
int maxi = -1;
int a1, a2;
min = check.Min();
maxi = check.Max();
median = check[lennn / 2];
a1 = median - min;
a2 = maxi - median;
int b1, b2;
b1 = zxy - min;
b2 = maxi - zxy;
if (a1 > 0 && a2 > 0)
{
if (b1 > 0 && b2 > 0)
{
marr[n + 1, z + 1] = Convert.ToByte(zxy);
z++;
if (z + (size - 1) > (width + 1))
{
n++;
z = 0;
}
}
else
{
marr[n + 1, z + 1] = Convert.ToByte(median);
z++;
if (z + (size - 1) > (width + 1))
{
n++;
z = 0;
}
}
}
else
{
size = size + 2;
if (size <= msize)
goto repeat;
else
{
marr[n +1, z +1] = Convert.ToByte(median);
z++;
if (size > 3)
size = 3;
if (z + (size - 1) > (width + 1))
{
n++;
z = 0;
}
}
}
}
return marr;
}
public static byte[] counting(byte[] array1D, int siz)
{
int max = -10000000;
byte[] SortedArray = new byte[siz * siz];
max = array1D.Max();
byte[] Array2 = new byte[max + 1];
//for (int i = 0; i < Array2.Length; i++)
// Array2[i] = 0; // create new array ( Array2) with zeros in every index .
for (int i = 0; i < (siz*siz); i++)
{
Array2[array1D[i]] += 1; //take the element in the index(i) of(array1d) AS the index of (Array2)
// and increment the element in this index by 1 .
}
for (int i = 1; i <= max; i++)
{
Array2[i] += Array2[i - 1]; // Count every element in (array1d) and put it in (Array2).
}
for (int i = (siz*siz) - 1; i >= 0; i--)
{
SortedArray[Array2[array1D[i]] - 1] = array1D[i]; // transfer the element in index (i) of (array1d) to (SortedArray
Array2[array1D[i]]--;
}
return SortedArray;
}
}
}
Any help will be appreciated, thank you.

How to remove empty spaces from PNG images and re-save them

Alright i don't know this is possible programmatically or not with any software but lets learn it.
Now let me demonstrate it with example
i am using paint.net magic wand tolerance 0%
empty space
and here empty space removed version
is this possible to do via any software such as c# or photoshop etc
i need to do batch processing
ty
I do not really know whether this answers your question or not but I hope it does
Here's a code to remove surrounding white space from an image from Darren
public static Bitmap Crop(Bitmap bmp)
{
int w = bmp.Width;
int h = bmp.Height;
Func<int, bool> allWhiteRow = row =>
{
for (int i = 0; i < w; ++i)
if (bmp.GetPixel(i, row).R != 255)
return false;
return true;
};
Func<int, bool> allWhiteColumn = col =>
{
for (int i = 0; i < h; ++i)
if (bmp.GetPixel(col, i).R != 255)
return false;
return true;
};
int topmost = 0;
for (int row = 0; row < h; ++row)
{
if (allWhiteRow(row))
topmost = row;
else break;
}
int bottommost = 0;
for (int row = h - 1; row >= 0; --row)
{
if (allWhiteRow(row))
bottommost = row;
else break;
}
int leftmost = 0, rightmost = 0;
for (int col = 0; col < w; ++col)
{
if (allWhiteColumn(col))
leftmost = col;
else
break;
}
for (int col = w - 1; col >= 0; --col)
{
if (allWhiteColumn(col))
rightmost = col;
else
break;
}
if (rightmost == 0) rightmost = w; // As reached left
if (bottommost == 0) bottommost = h; // As reached top.
int croppedWidth = rightmost - leftmost;
int croppedHeight = bottommost - topmost;
if (croppedWidth == 0) // No border on left or right
{
leftmost = 0;
croppedWidth = w;
}
if (croppedHeight == 0) // No border on top or bottom
{
topmost = 0;
croppedHeight = h;
}
try
{
var target = new Bitmap(croppedWidth, croppedHeight);
using (Graphics g = Graphics.FromImage(target))
{
g.DrawImage(bmp,
new RectangleF(0, 0, croppedWidth, croppedHeight),
new RectangleF(leftmost, topmost, croppedWidth, croppedHeight),
GraphicsUnit.Pixel);
}
return target;
}
catch (Exception ex)
{
throw new Exception(
string.Format("Values are topmost={0} btm={1} left={2} right={3} croppedWidth={4} croppedHeight={5}", topmost, bottommost, leftmost, rightmost, croppedWidth, croppedHeight),
ex);
}
}
Thanks,
I hope this helps :)

Categories

Resources