I trying to identify text in an image.
Actually I'm trying to identify the text positions in the image then convert it to text.
I found a some code written on c++ and I am trying to convert it to c#.
Can you help me please?
Extracting text OpenCV
std::vector<cv::Rect> detectLetters(cv::Mat img)
{ std::vector<cv::Rect> boundRect;[enter image description here][1]
cv::Mat img_gray, img_sobel, img_threshold, element;
cvtColor(img, img_gray, CV_BGR2GRAY);
cv::Sobel(img_gray, img_sobel, CV_8U, 1, 0, 3, 1, 0, cv::BORDER_DEFAULT);
cv::threshold(img_sobel, img_threshold, 0, 255, CV_THRESH_OTSU+CV_THRESH_BINARY);
element = getStructuringElement(cv::MORPH_RECT, cv::Size(10, 15) );
cv::morphologyEx(img_threshold, img_threshold, CV_MOP_CLOSE, element); //Does the trick
std::vector< std::vector< cv::Point> > contours;
cv::findContours(img_threshold, contours, 0, 1);
std::vector<std::vector<cv::Point> > contours_poly( contours.size() );
for( int i = 0; i < contours.size(); i++ )
if (contours[i].size()>80)
{
cv::approxPolyDP( cv::Mat(contours[i]), contours_poly[i], 17, true );
cv::Rect appRect( boundingRect( cv::Mat(contours_poly[i]) ));
if (appRect.width>appRect.height)
boundRect.push_back(appRect);
}
return boundRect;
}
and i try to convert it to c#, but it didn't work
private List<Rectangle> detectLetters(IntPtr img)
{
//cvtColor(img, img_gray, CV_BGR2GRAY);
List<Rectangle> boundRect = new List<Rectangle>();
//cv::Mat img_gray, img_sobel, img_threshold, element;
IntPtr
img_gray = IntPtr.Zero,
img_sobel= IntPtr.Zero,
img_threshold= IntPtr.Zero,
img_tmp = IntPtr.Zero,
element= IntPtr.Zero;
//cvtColor(img, img_gray, CV_BGR2GRAY);
CvInvoke.cvCvtColor(img, img_gray,COLOR_CONVERSION.CV_BGR2GRAY); //CV_BGR2GRAY);
//cv::Sobel(img_gray, img_sobel, CV_8U, 1, 0, 3, 1, 0, cv::BORDER_DEFAULT);
CvInvoke.cvSobel(img_gray, img_sobel, 0, 1, 1);//, 3, 1, 0, cv.BORDER_DEFAULT);
//cv.threshold(img_sobel, img_threshold, 0, 255, CV_THRESH_OTSU + CV_THRESH_BINARY);
CvInvoke.cvThreshold(img_sobel, img_threshold, 0, 255, THRESH.CV_THRESH_BINARY|THRESH.CV_THRESH_OTSU);
//element = getStructuringElement(cv.MORPH_RECT, cv.Size(10, 15));
element = CvInvoke.cvCreateStructuringElementEx(1,1,10,15,CV_ELEMENT_SHAPE.CV_SHAPE_RECT,element);// GetStructuringElement(
//cv.morphologyEx(img_threshold, img_threshold, CV_MOP_CLOSE, element); //Does the trick
CvInvoke.cvMorphologyEx(img_threshold,img_threshold,img_tmp,element,CV_MORPH_OP.CV_MOP_CLOSE,1);
//List<List<cv.Point>> contours = new List<List<cv.Point>>();
var contours = new List<IntPtr>();
//cv.findContours(img_threshold, contours, 0, 1);
CvInvoke.cvFindContours(img_threshold, element,ref ((IntPtr)contours[0]), 1, RETR_TYPE.CV_RETR_EXTERNAL, CHAIN_APPROX_METHOD.CV_CHAIN_APPROX_NONE,new Point(0,0));
//std::vector<std::vector<cv::Point> > contours_poly( contours.size() );
var contours_poly = new List<List<Point>>(contours.Count);
//for( int i = 0; i < contours.size(); i++ )
for (int i = 0; i < contours.Count; i++)
{
//if (contours[i].size()>80)
if (contours[i].ToInt32() > 80)
{
//cv.approxPolyDP(Emgu.CV.Matrix<>(contours[i]), contours_poly[i], 17, true);
CvInvoke.cvApproxPoly(contours[i], 17,contours_poly[i],APPROX_POLY_TYPE.CV_POLY_APPROX_DP, 1,1);
//cv::Rect appRect( boundingRect( cv::Mat(contours_poly[i]) ));
Rectangle appRect = new Rectangle(CvInvoke.cvBoundingRect(contours_poly[i],false));
//if (appRect.width>appRect.height)
if (appRect.width > appRect.height)
{
//boundRect.push_back(appRect);
boundRect.Add(appRect);
}
}
}
//return boundRect;
return boundRect;
}
Depending on what the size of the text you're looking for, you may have to play around with the variables for element size and ApproxPolyDP but this code is pretty close to the original but in OpenCvSharp lingo.
static List<Rect> RunTextRecog(string inFile)
{
List<Rect> boundRect = new List<Rect>();
using (Mat img = new Mat(inFile))
using (Mat img_gray = new Mat())
using (Mat img_sobel = new Mat())
using (Mat img_threshold = new Mat())
{
Cv2.CvtColor(img, img_gray, ColorConversionCodes.BGR2GRAY);
Cv2.Sobel(img_gray, img_sobel, MatType.CV_8U, 1, 0, 3, 1, 0, BorderTypes.Default);
Cv2.Threshold(img_sobel, img_threshold, 0, 255, ThresholdTypes.Otsu | ThresholdTypes.Binary);
using (Mat element = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(10, 15)))
{
Cv2.MorphologyEx(img_threshold, img_threshold, MorphTypes.Close, element);
Point[][] edgesArray = img_threshold.Clone().FindContoursAsArray(RetrievalModes.External, ContourApproximationModes.ApproxNone);
foreach (Point[] edges in edgesArray)
{
Point[] normalizedEdges = Cv2.ApproxPolyDP(edges, 17, true);
Rect appRect = Cv2.BoundingRect(normalizedEdges);
boundRect.Add(appRect);
}
}
}
return boundRect;
}
Related
i am using C# EmguCv library to detect diamonds from the image capture by a live camera and saved into the folder. i have done other task of the project and only remaining the detection part and almost got it but just missing something that i don't know where is the problem . so here is the Image and it should be detected as Image2 perfect as this image so now i am trying something but it not giving me the result i want. here's i what i am getting is image3 and image4.
here is my code:
imgInput = new Image<Bgr, byte>(img_path);
if (imgInput == null)
{
return;
}
try
{
// Convert image to grayscale
Mat grayImage = new Mat();
CvInvoke.CvtColor(imgInput, grayImage, ColorConversion.Bgr2Gray);
// Apply Gaussian blur to reduce noise
CvInvoke.GaussianBlur(grayImage, grayImage, new Size(7, 7), 4);
// Apply Canny edge detection
Mat edges = new Mat();
CvInvoke.Canny(grayImage, edges, 75, 200);
VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint();
CvInvoke.FindContours(edges, contours, null, RetrType.List, ChainApproxMethod.ChainApproxSimple);
int jk = 0;
dataGridView1.Columns.Add("stone_id", "Stone ID");
for (int i = 0; i < contours.Size; i++)
{
double perimeter = CvInvoke.ArcLength(contours[i], true);
VectorOfPoint approx = new VectorOfPoint();
CvInvoke.ApproxPolyDP(contours[i], approx, 0.04 * perimeter, true);
var bbox = CvInvoke.BoundingRectangle(contours[i]);
process_img = new Image<Bgr, byte>(img_path);
process_img.ROI = bbox;
var img = process_img.Copy();
if (jk == sel_row_id)
{
CvInvoke.DrawContours(imgInput, contours, i, new MCvScalar(0, 255, 17), 2);
if (contours.Size > 0)
{
byte maxRed, maxBlue, maxGreen;
maxRed = maxBlue = maxGreen = 0;
float meanRed, meanBlue, meanGreen;
meanRed = meanBlue = meanGreen = 0;
double medRed,medBlue,medGreen;
medRed = medBlue = medGreen = 0;
FindMax(img.Bitmap, ref maxRed, ref maxBlue, ref maxGreen, ref meanRed, ref meanBlue, ref meanGreen, ref medRed, ref medBlue, ref medGreen);
R_txtbox.Text = maxRed.ToString();
B_txtbox.Text = maxBlue.ToString();
G_txtbox.Text = maxGreen.ToString();
R_mean.Text = meanRed.ToString();
B_mean.Text = meanBlue.ToString();
G_mean.Text = meanGreen.ToString();
R_med.Text = medRed.ToString();
B_med.Text = medBlue.ToString();
G_med.Text = medGreen.ToString();
pictureBox5.Image = img.ToBitmap();
//colorCode.Text = myRgbColor.ToString();
}
}
else
{
CvInvoke.DrawContours(imgInput, contours, i, new MCvScalar(0, 0, 255), 2);
}
dataGridView1.Rows.Add(jk.ToString());
jk++;
pictureBox4.Image = imgInput.Bitmap;
img.Save("F:\\Objects" + "\\" + (i + 1) + ".jpg");
}
RefreshGridView();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
I have an ellipse which is growing with time.
To detect the ellipse I have used CvInvoke.AbsDiff method .
and I gets an image like this
I want to put this ellipse to fit-ellipse method and gain the radius es of it.
This is the approach I took.
CvInvoke.AbsDiff(First, img, grayscale);
CvInvoke.CvtColor(grayscale, grayscale, ColorConversion.Bgr2Gray);
CvInvoke.GaussianBlur(grayscale, grayscale, new System.Drawing.Size(11, 11), 15, 15);
CvInvoke.Threshold(grayscale, grayscale, Convert.ToInt16(Threshold), Convert.ToInt16(Threshold * 2), ThresholdType.Binary );
Mat element = CvInvoke.GetStructuringElement(Emgu.CV.CvEnum.ElementShape.Rectangle, new System.Drawing.Size(3, 3), new System.Drawing.Point(-1, -1));
CvInvoke.Dilate(grayscale, grayscale, element, new System.Drawing.Point(-1, 1), 5, BorderType.Constant, new MCvScalar(255, 255, 255));
CvInvoke.Canny(grayscale, grayscale, Threshold, MaxThreshold * 2, 3);
VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint();
CvInvoke.FindContours(grayscale, contours, null, RetrType.Ccomp, ChainApproxMethod.ChainApproxTc89Kcos);
double area = 0;
double ContourArea = 0;
int contour = 0;
int CenterX;
int CenterY;
for (int i = 0; i < contours.Size; i++)
{
System.Drawing.Rectangle rec = CvInvoke.BoundingRectangle(contours[i]);
output.Draw(rec, new Bgr(255, 0, 255), 2);
CenterX = ((rec.Width) / 2) + rec.X;
CenterY = ((rec.Height) / 2) + rec.Y;
ContourArea = rec.Width * rec.Height; ;
if ((HWidth - CenterFactor) < CenterX && CenterX < (HWidth + CenterFactor) && (HHeight - CenterFactor) < CenterY && CenterY< (HHeight + CenterFactor) )
{
if (ContourArea < 1000000)
if (area < ContourArea)
{
area = ContourArea;
contour = i;
}
}
}
//if (contour == 0)
//{
// return arr;
//}
System.Drawing.Rectangle rect = CvInvoke.BoundingRectangle(contours[contour]);
output.Draw(rect, new Bgr(0, 255, 0), 3);
But i am not getting the best ellipse everytime. This is the contour which I'm getting
Is there any other way to do this?
Although this method is not completely perfect, this could be a possible direction that you could take.
Mat input = CvInvoke.Imread(#"C:\Users\ajones\Desktop\Images\inputImg.png", ImreadModes.AnyColor);
Mat input2 = input.Clone();
Mat thresh = new Mat();
CvInvoke.GaussianBlur(input, thresh, new System.Drawing.Size(7, 7), 10, 10);
CvInvoke.Threshold(thresh, thresh, 3, 10, ThresholdType.Binary);
CvInvoke.Imshow("The Thresh", thresh);
CvInvoke.WaitKey(0);
Mat output = new Mat();
CvInvoke.CvtColor(thresh, output, ColorConversion.Bgr2Gray);
VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint();
CvInvoke.FindContours(output, contours, null, RetrType.External, ChainApproxMethod.ChainApproxSimple);
CvInvoke.DrawContours(input, contours, -1, new MCvScalar(0, 255, 0), 3, LineType.FourConnected);
CvInvoke.Imshow("The Image", input);
CvInvoke.WaitKey(0);
int biggest = 0;
int index = 0;
for (int i = 0; i<contours.Size; i++)
{
if (contours[i].Size > biggest)
{
biggest = contours[i].Size;
index = i;
}
}
CvInvoke.DrawContours(input2, contours, index, new MCvScalar(0, 255, 0), 3, LineType.FourConnected);
CvInvoke.Imshow("The Image2", input2);
CvInvoke.WaitKey(0);
First blur the image using a Gaussian filter.
Then, using a binary threshold.
Afterwards, find all contours on the image
Finally, all you would need to do is just sort through your contours until you found the biggest one.
Like I said, its not completely perfect, but I should help push you in the right direction.
With the function below, I'm running into problems trying to access the WriteableBitmap.PixelBuffer property. The message I am getting is:
'WriteableBitmap' does not contain a definition for 'PixelBuffer' and no extension method 'PixelBuffer' accepting a first argument of type 'WriteableBitmap' could be found (are you missing a using directive or an assembly reference?)
I have read other places that I need to include
using System.Runtime.InteropServices.WindowsRuntime;
But when I use this include, nothing changes in my code. Looking through the references of my solution, I don't see anything like System.Runtime.InteropServices. Im frustrated as this seems to be the solution to other people trying to access the PixelBuffer of a WriteableBitmap.
private WriteableBitmap ChangeBrightness(WriteableBitmap source, byte change_value)
{
WriteableBitmap dest = new WriteableBitmap(source);
byte[] color = new byte[4];
using (Stream s = source.PixelBuffer.AsStream())
{
using (Stream d = dest.PixelBuffer.AsStream())
{
// read the pixel color
while (s.Read(color, 0, 4) > 0)
{
// color[0] = b
// color[1] = g
// color[2] = r
// color[3] = a
// do the adding algo per byte (skip the alpha)
for (int i = 0; i < 4; i++)
{
if ((int)color[i] + change_value > 255) color[i] = 255; else color[i] = (byte)(color[i] + change_value);
}
// write the new pixel color
d.Write(color, 0, 4);
}
}
}
// return the new bitmap
return dest;
}
Make sure you are referencing the assembly that package belongs to:
System.Runtime.WindowsRuntime assembly
I've ended up going about solving my original problem via other means. To adjust the brightness of my image, I ended up using this functions instead:
public ImageSource AdjustBrightness(BitmapImage Image, int Value, int mod)
{
Bitmap TempBitmap = BitmapImage2Bitmap(Image);
Bitmap NewBitmap = new Bitmap(TempBitmap.Width, TempBitmap.Height);
Graphics NewGraphics = Graphics.FromImage(NewBitmap);
float FinalValue = (float)Value / 255.0f;
float[][] FloatColorMatrix ={
new float[] {1, 0, 0, 0, 0},
new float[] {0, 1, 0, 0, 0},
new float[] {0, 0, 1, 0, 0},
new float[] {0, 0, 0, 1, 0},
new float[] {mod * FinalValue, mod * FinalValue, mod * FinalValue, 1, 1}
};
ColorMatrix NewColorMatrix = new ColorMatrix(FloatColorMatrix);
ImageAttributes Attributes = new ImageAttributes();
Attributes.SetColorMatrix(NewColorMatrix);
NewGraphics.DrawImage(TempBitmap, new Rectangle(0, 0, TempBitmap.Width, TempBitmap.Height), 0, 0, TempBitmap.Width, TempBitmap.Height, GraphicsUnit.Pixel, Attributes);
Attributes.Dispose();
NewGraphics.Dispose();
return Bitmap2BitmapImage(NewBitmap);
}
Regarding this Opencv Tutorial, the following C++ code snippet:
vector<Vec4i> lines;
// Find hough lines
HoughLinesP(edges, lines, 1, CV_PI / 180, 100, 100, 10);
// Prepare blank mat with same sizes as image
Mat Blank(image.rows, image.cols, CV_8UC3, Scalar(0, 0, 0));
// Draw lines into image and Blank images
for (size_t i = 0; i < lines.size(); i++)
{
Vec4i l = lines[i];
line(image, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(0, 0, 0), 2, CV_AA);
line(Blank, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(255, 255, 255), 2, CV_AA);
}
has been translated into C# like this:
private void openFileDialogButton_Click(object sender, EventArgs e)
{
try
{
const string filename = #"E:\___MSc in Computer Systems & Network\EMSC1,2,3\lena.png";
Mat image = Cv2.ImRead(filename, LoadMode.GrayScale);
Mat edges = new Mat();
Cv2.Canny(image, edges, 95, 100);
Cv2.ImWrite("edges.jpg", edges);
Mat dx = new Mat();
Mat dy = new Mat();
Cv2.Sobel(edges, dx, MatType.CV_32F, 1, 0);
Cv2.Sobel(edges, dy, MatType.CV_32F, 0, 1);
Cv2.ImWrite("dx.jpg", dx);
Cv2.ImWrite("dy.jpg", dy);
Mat linesssssss = new Mat();
Cv.HoughLines2((CvArr)linesssssss.ToIplImage(),
(CvMat)edges,
HoughLinesMethod.Standard,
1,
Math.PI / 180,
100, 100, 10);
//Cv2.HoughLinesP(edges, lines, 1, Math.PI / 180, 100, 100, 10);
List<Vec4i> lines = IntPtrToList(linesssssss.Data);
Mat Blank = new Mat(image.Rows, image.Cols, MatType.CV_8UC3, new Scalar(0, 0, 0));
for (int i = 0; i < lines.Count; i++)
{
Vec4i l = lines[i];
Cv2.Line(image, new OpenCvSharp.CPlusPlus.Point(l[0], l[1]), new OpenCvSharp.CPlusPlus.Point(l[2], l[3]), new Scalar(0, 0, 0), 2, Cv.AA);
Cv2.Line(Blank, new OpenCvSharp.CPlusPlus.Point(l[0], l[1]), new OpenCvSharp.CPlusPlus.Point(l[2], l[3]), new Scalar(255, 255, 255), 2, Cv.AA);
}
//Cv2.ImWrite("houg.jpg", image);
//Cv2.ImShow("Edges", image);
//Cv2.ImWrite("houg2.jpg", Blank);
//Cv2.ImShow("Edges Structure", Blank);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
Unfortunately, it seems to be not working. It is giving the following exception:
Nonpositive cols or rows
This is the original image from the article:
Based on Github's sample code for HoughLinesP:
static void Main(string[] args)
{
string filename = "Alliance.jpg";
Mat imageIn = Cv2.ImRead(filename, ImreadModes.GrayScale).Resize(new Size(800, 600));
Mat edges = new Mat();
Cv2.Canny(imageIn, edges, 95, 100);
//HoughLinesP
LineSegmentPoint[] segHoughP = Cv2.HoughLinesP(edges, 1, Math.PI / 180, 100, 100, 10);
Mat imageOutP = imageIn.EmptyClone();
foreach (LineSegmentPoint s in segHoughP)
imageOutP.Line(s.P1, s.P2, Scalar.White, 1, LineTypes.AntiAlias, 0);
using (new Window("Edges", WindowMode.AutoSize, edges))
using (new Window("HoughLinesP", WindowMode.AutoSize, imageOutP))
{
Window.WaitKey(0);
}
}
I want to invert an Image object. Currently my code looks like this:
private Image Invert(Image img)
{
var bmpPicture = new Bitmap(img.Width, img.Height);
var iaPicture = new ImageAttributes();
var cmPicture = new ColorMatrix { Matrix00 = -1, Matrix11 = -1, Matrix22 = -1 };
iaPicture.SetColorMatrix(cmPicture);
var gfxPicture = Graphics.FromImage(img);
var rctPicture = new Rectangle(0, 0, img.Width, img.Height);
gfxPicture.DrawImage(img, rctPicture, 0, 0, img.Width, img.Height, GraphicsUnit.Pixel, iaPicture);
return bmpPicture;
}
However, when I run this, and show it in a PictureBox, the result is a black image. I'm running this in Visual Studio 2012 under Windows 8 Release preview. If there is a better way to do this, please let me know. Thanks.
Try this: http://mariusbancila.ro/blog/2009/11/13/using-colormatrix-for-creating-negative-image/
public Bitmap Transform(Bitmap source)
{
//create a blank bitmap the same size as original
Bitmap newBitmap = new Bitmap(source.Width, source.Height);
//get a graphics object from the new image
Graphics g = Graphics.FromImage(newBitmap);
// create the negative color matrix
ColorMatrix colorMatrix = new ColorMatrix(new float[][]
{
new float[] {-1, 0, 0, 0, 0},
new float[] {0, -1, 0, 0, 0},
new float[] {0, 0, -1, 0, 0},
new float[] {0, 0, 0, 1, 0},
new float[] {1, 1, 1, 0, 1}
});
// create some image attributes
ImageAttributes attributes = new ImageAttributes();
attributes.SetColorMatrix(colorMatrix);
g.DrawImage(source, new Rectangle(0, 0, source.Width, source.Height),
0, 0, source.Width, source.Height, GraphicsUnit.Pixel, attributes);
//dispose the Graphics object
g.Dispose();
return newBitmap;
}
Fast alternative to using a ColorMatrix for pixel manipulation:
public static void BitmapInvertColors(Bitmap bitmapImage)
{
var bitmapRead = bitmapImage.LockBits(new Rectangle(0, 0, bitmapImage.Width, bitmapImage.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppPArgb);
var bitmapLength = bitmapRead.Stride * bitmapRead.Height;
var bitmapBGRA = new byte[bitmapLength];
Marshal.Copy(bitmapRead.Scan0, bitmapBGRA, 0, bitmapLength);
bitmapImage.UnlockBits(bitmapRead);
for (int i = 0; i < bitmapLength; i += 4)
{
bitmapBGRA[i] = (byte)(255 - bitmapBGRA[i]);
bitmapBGRA[i + 1] = (byte)(255 - bitmapBGRA[i + 1]);
bitmapBGRA[i + 2] = (byte)(255 - bitmapBGRA[i + 2]);
// [i + 3] = ALPHA.
}
var bitmapWrite = bitmapImage.LockBits(new Rectangle(0, 0, bitmapImage.Width, bitmapImage.Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppPArgb);
Marshal.Copy(bitmapBGRA, 0, bitmapWrite.Scan0, bitmapLength);
bitmapImage.UnlockBits(bitmapWrite);
}
VB version of Dan's Answer. It works like a charm !!
Public Function Transform(source As Bitmap) As Bitmap
'create a blank bitmap the same size as original
Dim newBitmap As New Bitmap(source.Width, source.Height)
'get a graphics object from the new image
Dim g As Graphics = Graphics.FromImage(newBitmap)
' create the negative color matrix
Dim colorMatrix As New ColorMatrix(New Single()() {New Single() {-1, 0, 0, 0, 0}, New Single() {0, -1, 0, 0, 0}, New Single() {0, 0, -1, 0, 0}, New Single() {0, 0, 0, 1, 0}, New Single() {1, 1, 1, 0, 1}})
' create some image attributes
Dim attributes As New ImageAttributes()
attributes.SetColorMatrix(colorMatrix)
g.DrawImage(source, New Rectangle(0, 0, source.Width, source.Height), 0, 0, source.Width, source.Height, _
GraphicsUnit.Pixel, attributes)
'dispose the Graphics object
g.Dispose()
Return newBitmap
End Function
You aren't setting Matrix33 or Matrix44. My understanding is that Matrix33 would be the alpha component, so I suspect you're making your entire image transparent.
Try setting Matrix33 = 1.
I used "SIMD Supported Vectors" to make a code faster then pointers.Its under System.Numerics namespace.But before using these classes you need to get the update for System.Numerics from NuGet.Just search for System.Numerics.Anyways thats my class to invert the image
public class VBitmap : IDisposable
{
public short Width { get; private set; }
public short Height { get; private set; }
public int Stride { get; private set; }
public int PixelLenght { get; private set; }
public byte BytesperPixel { get; private set; }
public PixelFormat PixelFormat { get; private set; }
public byte[] Pixels { get; private set; }
public VBitmap(string path)
{
using (Bitmap bmp = new Bitmap(path))
{
BitmapData bmpdata = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, bmp.PixelFormat);
Width = checked((short)bmp.Width);
Height = checked((short)bmp.Height);
Stride = bmpdata.Stride;
PixelLenght = Stride * Height;
BytesperPixel = checked((byte)(Stride / Width));
PixelLenght = (PixelLenght % 16) != 0 ? PixelLenght + (PixelLenght % 16) : PixelLenght;
PixelFormat = bmp.PixelFormat;
Pixels = new byte[PixelLenght];
Marshal.Copy(bmpdata.Scan0, Pixels, 0, PixelLenght);
bmp.UnlockBits(bmpdata);
}
}
~VBitmap()
{
Dispose();
}
public void InvertPixels()
{
byte[] resultarray = Pixels;
unsafe
{
fixed (byte* result_ptr = resultarray)
{
for (int i = 0; i < PixelLenght; i += 16)
(~new Vector<byte>(Pixels, i)).CopyTo(resultarray, i);
}
}
}
public void InvertPixels(string name)
{
byte[] resultarray = Pixels;
unsafe
{
fixed (byte* result_ptr = resultarray)
{
for (int i = 0; i < PixelLenght; i += 16)
(~new Vector<byte>(Pixels, i)).CopyTo(resultarray, i);
SaveImage(name);
}
}
}
public unsafe void SaveImage(string name)
{
fixed (byte* p_ptr = Pixels)
{
using (Bitmap resultbmp = new Bitmap(Width, Height, Stride, PixelFormat, (IntPtr)p_ptr))
{
resultbmp.Save(name, ImageFormat.Jpeg);
}
}
}
public void Dispose()
{
Width = 0;
Height = 0;
Stride = 0;
PixelLenght = 0;
BytesperPixel = 0;
Pixels = null;
GC.Collect();
}
}
Usage.Note:To get best performance from vectors you need to run your code on Release Mode:
static void Main(string[] args)
{
new VBitmap("testp.png").InvertPixels("qq.jpg");//Inverts the given bitmap and saves it.
}
By inverting, do you mean creating a negative? If yes here is a snippet:
public void ApplyInvert()
{
byte A, R, G, B;
Color pixelColor;
for (int y = 0; y < bitmapImage.Height; y++)
{
for (int x = 0; x < bitmapImage.Width; x++)
{
pixelColor = bitmapImage.GetPixel(x, y);
A = pixelColor.A;
R = (byte)(255 - pixelColor.R);
G = (byte)(255 - pixelColor.G);
B = (byte)(255 - pixelColor.B);
bitmapImage.SetPixel(x, y, Color.FromArgb((int)A, (int)R, (int)G, (int)B));
}
}
}
from: http://www.smokycogs.com/blog/image-processing-in-c-sharp-inverting-an-image/
If you want read more about your problem and color matrix, please proceed with the following link: https://web.archive.org/web/20141230042200/http://bobpowell.net/negativeimage.aspx
var gfxPicture = Graphics.FromImage(img);
==>
var gfxPicture = Graphics.FromImage(bmpPicture);
DrawImage could distort image, GetPixel is slow, Try WPF imaging API