opencv read text in image c#(visual studio) - c#

Hi everybody I wrote a code for text detection with opencv But I have got a mistake My code cant entire the forecah Here is my code
public int FindWrite()
{
// aimg = new IplImage(img.Size, BitDepth.U8, 1);
IplImage labelImage = new IplImage(img.Size, CvBlobLib.DepthLabel, 1);
labelImage = new IplImage(img.Size, BitDepth.U8,1);
blob = new CvBlobs();
text.Clear();
CvBlobLib.Label(labelImage,blob);
CvBlobLib.FilterByArea(blob, 600, 10000);
IplImage imgtemp = img.Clone();
// CvBlobLib.RenderBlobs(blob, img, imgtemp, RenderBlobsMode.BoundingBox | RenderBlobsMode.Angle);
// CvBlobLib.RenderBlobs(blob,img, imgtemp, RenderBlobsMode.BoundingBox | RenderBlobsMode.Angle);
CvBlobLib.RenderBlobs(blob,labelImage, imgtemp, RenderBlobsMode.BoundingBox | RenderBlobsMode.Angle);
// CvBlobLib.RenderBlobs(blob, labelImage, imgtemp, RenderBlobsMode.BoundingBox | RenderBlobsMode.Angle);
foreach (var item in blob)
{
item.Value.SetImageRoiToBlob(bimg);
// ratio values of plate between 3.5 and 5.4
double ratio = (double)item.Value.Rect.Width / item.Value.Rect.Height;
double angle = (double)item.Value.Angle();
if (ratio > 3.5 && ratio < 5.4 && angle > -15 && angle < 15)
{
IplImage texttemp = new IplImage(new CvSize(140, 27), bimg.Depth, bimg.NChannels);
Cv.Resize(bimg, texttemp);
text.Add(texttemp);
img.Rectangle(item.Value.Rect, new CvScalar(0, 0, 255), 2, LineType.Link4);
}
}
img.ResetROI();
return text.Count;
}
thanks your advance

Related

How to implement unsharp masking on emgucv c#

I am trying to implement the unsharp masking method on emgucv using c#.
The python code I have now is (ref):
def unsharp_mask(image, kernel_size=(5, 5), sigma=1.0, amount=1.0, threshold=0):
"""Return a sharpened version of the image, using an unsharp mask."""
# For details on unsharp masking, see:
# https://en.wikipedia.org/wiki/Unsharp_masking
# https://homepages.inf.ed.ac.uk/rbf/HIPR2/unsharp.htm
blurred = cv.GaussianBlur(image, kernel_size, sigma)
sharpened = float(amount + 1) * image - float(amount) * blurred
sharpened = np.maximum(sharpened, np.zeros(sharpened.shape))
sharpened = np.minimum(sharpened, 255 * np.ones(sharpened.shape))
sharpened = sharpened.round().astype(np.uint8)
if threshold > 0:
low_contrast_mask = np.absolute(image - blurred) < threshold
np.copyto(sharpened, image, where=low_contrast_mask)
return sharpened
The c# code I have now cannot do the work as the above code does. Does anyone know how to implement it emgu cv using c#?
public static void GetMat(Image<Gray, byte> srcimg, Image<Gray, byte> imgBlurred, ref Mat dst, int nAmount = 200)
{
float amount = nAmount / 100f;
using (Image<Gray, byte> dst_temp = new Image<Gray, byte>(srcimg.Width, srcimg.Height))
{
for (int v = 0; v < srcimg.Height; v++)
{
for (int u = 0; u < srcimg.Width; u++)
{
byte a = srcimg.Data[v, u, 0]; //Get Pixel Color | fast way
byte b = imgBlurred.Data[v, u, 0];
int c = (int)(a * (1 + amount) - (amount * b));
if (c < 0) c = 0;
if (c > 255) c = 255;
dst_temp.Data[v, u, 0] = (byte)c;
}
}
dst = dst_temp.Mat.Clone();
}
}
public static void getSharpenImage(Mat src, ref Mat dst, int nAmount = 200, double sigma = 3, int threshold = 0)
{
float amount = nAmount / 100.0F;
using (Mat imgBlurred = new Mat())
{
CvInvoke.GaussianBlur(src, imgBlurred, new System.Drawing.Size(0, 0), sigma, sigma);
using (Mat mask_temp = new Mat())
{
CvInvoke.AbsDiff(src, imgBlurred, mask_temp);
using (Mat lowcontrastmask = new Mat())
{
CvInvoke.Threshold(mask_temp, lowcontrastmask, threshold, 255, ThresholdType.BinaryInv);
GetMat(src.ToImage<Gray, byte>(), imgBlurred.ToImage<Gray, byte>(), ref dst);
src.CopyTo(dst, lowcontrastmask);
}
}
}
}
https://www.idtools.com.au/unsharp-masking-python-opencv/ has a python solution.
the following works in C#:
Mat blurredImage = new Mat();
Mat lapImage = new Mat();
CvInvoke.MedianBlur(grayImage, blurredImage, 1);
CvInvoke.Laplacian(blurredImage, lapImage, blurredImage.Depth);
blurredImage -= (0.9*lapImage);

Set Specified region for Motion Detection

I need to specify a region on where motion detection will occur. What I am trying to do is count the number of vehicles that passes a certain region. Below is my code:
private static void ProcessFrame(Mat backgroundFrame, int threshold, int erodeIterations, int dilateIterations)
{
// Find difference between background (first) frame and current frame
CvInvoke.AbsDiff(backgroundFrame, rawFrame, diffFrame);
// Apply binary threshold to grayscale image (white pixel will mark difference)
CvInvoke.CvtColor(diffFrame, grayscaleDiffFrame, ColorConversion.Bgr2Gray);
CvInvoke.Threshold(grayscaleDiffFrame, binaryDiffFrame, threshold, 255, ThresholdType.Binary);
// Remove noise with opening operation (erosion followed by dilation)
CvInvoke.Erode(binaryDiffFrame, denoisedDiffFrame, null, new Point(-1, -1), erodeIterations, BorderType.Default, new MCvScalar(1));
CvInvoke.Dilate(denoisedDiffFrame, denoisedDiffFrame, null, new Point(-1, -1), dilateIterations, BorderType.Default, new MCvScalar(1));
rawFrame.CopyTo(finalFrame);
//Rectangle rec = new Rectangle(100, 100, 100, 100);
//finalFrame = crop_color_frame(rawFrame, rec);
var img = crop_color_frame(denoisedDiffFrame, rec);
DetectObject(denoisedDiffFrame, finalFrame);
}
static int vnum = 0;
private static void DetectObject(Mat detectionFrame, Mat displayFrame)
{
using (VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint())
{
// Build list of contours
CvInvoke.FindContours(detectionFrame, contours, null, RetrType.List, ChainApproxMethod.ChainApproxSimple);
// Selecting largest contour
if (contours.Size > 0)
{
double maxArea = 0;
int chosen = 0;
for (int i = 0; i < contours.Size; i++)
{
VectorOfPoint contour = contours[i];
double area = CvInvoke.ContourArea(contour);
if (area > maxArea)
{
maxArea = area;
chosen = i;
}
}
// Draw on a frame
MarkDetectedObject(displayFrame, contours[chosen], maxArea, contours.Size, maxArea);
}
}
}
private static void MarkDetectedObject(Mat frame, VectorOfPoint contour, double area, double contourSize, double maxArea)
{
// Getting minimal rectangle which contains the contour
Rectangle box = CvInvoke.BoundingRectangle(contour);
// Drawing contour and box around it
CvInvoke.Polylines(frame, contour, true, drawingColor);
CvInvoke.Rectangle(frame, box, drawingColor);
// Write information next to marked object
Point center = new Point(box.X + box.Width / 2, box.Y + box.Height / 2);
Point center2 = new Point(box.Width, box.Height);
var info = new string[] {
$"Area: {area}",
$"Position: {center.X}, {center.Y}"
};
Console.WriteLine($"X: {center.X} | Y: {center.Y} | Area: {area} | Count: {vnum} | Status: {vehicleState} | contour: {contour.Size}");
switch (vehicleState)
{
case VehicleState.Entering:
if(_startCount)
{
//if(((maxArea > 15000 && maxArea <= 20000) && center.Y <= 120) || ((maxArea >= 5000 && maxArea < 10000) && center.Y >= 150))
if(center.Y >= 100 && maxArea > 20000)
{
CountVehicle();
vehicleState = VehicleState.Exiting;
_startCount = false;
}
}
break;
case VehicleState.Exiting:
if (!_startCount)
{
//if(maxArea < 12000 && center.Y <= 120)
if(center.Y <= 130 && center.X <= 100 && maxArea <= 15000)
{
vehicleState = VehicleState.Entering;
_startCount = true;
}
}
break;
}
WriteMultilineText(frame, info, new Point(box.Right + 5, center.Y));
}
As of the moment, this code works on detecting vehicles but I am just using the
if(center.Y >= 100 && maxArea > 20000) condition to start counting the vehicles
the problem with that approach is, all movements in the frame are being monitored. That is why I need to set an specific region only.
Could you please show me how to do this?
You can set ROI for the input image
public static Mat crop_roi(Mat input_img)
{
Image<Gray, byte> img = input_img.ToImage<Gray, byte>();
double w = input_img.Width;
double h = input_img.Height;
Rectangle r = new Rectangle((int)(w * 0.2), (int)(h * 0.4), (int)(w * 0.6), (int)(h * 0.6));
Image<Gray, byte> output = img.Copy(r);
return output.Mat;
}
//USE
private static void DetectObject(Mat detectionFrame, Mat displayFrame)
{
using (VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint())
{
//set roi to the frame
Mat roi = new Mat()
roi = set_roi(detectionFrame);
// Build list of contours
CvInvoke.FindContours(roi , contours, null, RetrType.List, ChainApproxMethod.ChainApproxSimple);
// Selecting largest contour
...
MarkDetectedObject(roi , contours[chosen], maxArea, contours.Size, maxArea);
}
Below is the image I draw the ROI in an image, you can adjust the ROI by changing the parameter in this line Rectangle r = new Rectangle((int)(w * 0.2), (int)(h * 0.4), (int)(w * 0.6), (int)(h * 0.6));

C# Forms Print Image As Big As Possible [duplicate]

This question already has answers here:
c# Image resizing to different size while preserving aspect ratio
(14 answers)
Closed 4 years ago.
I want to print an image on Windows Forms, but I want to print the image as big as possible on the page without breaking its aspect ratio. Like when I want to print a simple square to A4 paper it becomes rectangle with this script:
private void Page(object sender, PrintPageEventArgs e)
{
Bitmap i = image;
if(e.PageBounds.Height > e.PageBounds.Width)
{
if (i.Width > i.Height)
i.RotateFlip(RotateFlipType.Rotate90FlipNone);
}
else if(e.PageBounds.Width > e.PageBounds.Height)
{
if (i.Height > i.Width)
i.RotateFlip(RotateFlipType.Rotate90FlipNone);
}
e.Graphics.DrawImage(i, new Rectangle(0, 0, e.PageBounds.Width, e.PageBounds.Height));
i.Dispose();
}
Original:
500x500 square
What I got (as pdf):
A rectangle on the A4 paper
Another example:
Original:Original image(313x234)
Print:Print image
I don't want to break the aspect ratio of the image
Try this:
private void Page(object sender, PrintPageEventArgs e)
{
using (Bitmap i = image) //are you *really sure* you want to dispose this after printing?
{
var pageRatio = e.PageBounds.Width / (double)e.PageBounds.Height;
var imageRatio = i.Width / (double)i.Height;
//do we need to rotate?
if ( (pageRatio < 1 && imageRatio > 1) || (pageRatio < 1 && imageRatio > 1))
{
i.RotateFlip(RotateFlipType.Rotate90FlipNone);
imageRatio = i.Width / (double)i.Height; //ratio will have changed after rotation
}
var scale = 1.0D;
//do we need to scale?
if (pageRatio > imageRatio)
{ //the page is wider than the image, so scale to the height
scale = e.PageBounds.Height / (double)i.Height;
}
else if (pageRatio < imageRatio)
{ //the page is narrower than the image, so scale to width
scale = e.PageBounds.Width / (double)i.Width;
}
var W = (int)(scale * i.Width);
var H = (int)(scale * i.Height);
e.Graphics.DrawImage(i, new Rectangle(0, 0, W, H));
}
}
This will always draw from the top left corner. If you want it centered, you need to make additional adjustments:
private void Page(object sender, PrintPageEventArgs e)
{
using (Bitmap i = image) //are you *really sure* you want to dispose this after printing?
{
var pageRatio = e.PageBounds.Width / (double)e.PageBounds.Height;
var imageRatio = i.Width / (double)i.Height;
//do we need to rotate?
if ( (pageRatio < 1 && imageRatio > 1) || (pageRatio < 1 && imageRatio > 1))
{
i.RotateFlip(RotateFlipType.Rotate90FlipNone);
imageRatio = i.Width / (double)i.Height; //ratio will have changed after rotation
}
int T = 0, L = 0; //top, left
var scale = 1.0D;
int W = i.Width, H = i.Height;
//do we need to scale?
if (pageRatio > imageRatio)
{ //the page is wider than the image, so scale to the height
scale = e.PageBounds.Height / (double)i.Height;
W = (int)(scale * i.Width);
H = (int)(scale * i.Height);
L = (e.PageBounds.Width - W)/2;
}
else if (pageRatio < imageRatio)
{ //the page is narrower than the image, so scale to width
scale = e.PageBounds.Width / (double)i.Width;
W = (int)(scale * i.Width);
H = (int)(scale * i.Height);
T = (e.PageBounds.Height - H)/2;
}
e.Graphics.DrawImage(i, new Rectangle(L, T, W+L, H+T));
}
}
The important thing is both the width and height are adjusted to the same scale... that is, multiplied by the same number.

Circular Fisheye Image dewarp to flat image

UPDATE as on 12 Nov 2015
I used PanoTools plugin with Photoshop and Hugin and played with all those parameters. End up i found the parameters for projection, HFOV and image output size that fulfill my lowest requirement.
Parameteres:
Processed Output:
My question is then how can i convert all these parameters and values into C# algorithm coding so that when I provide the original image, i will get the corrected output image?
Thanks a lot.
I have a square image captured from a circular fisheye camera. The size is 2650 * 2650 pixels.
Now, i will need to programmatically dewarp the image to a flat panorama image using C# language.
I had look around from internet with different algorithm example from Link for code below , Link1 and Link2 but just can't make it success. My maths sincerely sucks and can't help me with that. Hopefully someone able to guide me through this.
Thanks a lot.
Example of image output from the camera:
--Image grabbed from Wikipedia Fisheye Lens & size modified to fit my sample pixel.
The code i tried to dewarp it but no luck:
Bitmap sourceImage = (Bitmap)Bitmap.FromFile("circularfisheye.jpg");
double factor = 0.5;
Boolean autoCrop = false;
Color backgroundColor = Color.White;
Bitmap StartImage = null;
BitmapData srcBitmapData = null;
Byte[] srcPixels = null;
Byte[] dstPixels = null;
Bitmap NewImage = null;
BitmapData dstBitmapData = null;
try
{
// Checks whether bpp ​​( Bits Per Pixel ) is 8 , 24, or 32
int Depth = System.Drawing.Bitmap.GetPixelFormatSize(sourceImage.PixelFormat);
if (Depth != 8 && Depth != 24 && Depth != 32)
{
throw new ArgumentException("Only 8, 24 and 32 bpp images are supported.");
}
// Retrieves the count of the color components
int cCount = Depth / 8;
Size baseSize = new Size(sourceImage.Width, sourceImage.Height);
// check if a low image resize and need to improve the quality
// and not generate image aliasing
Int32 maxSize = Math.Max(sourceImage.Width, sourceImage.Height);
if (maxSize < 3000)
{
float percent = 3000F / (float)maxSize;
baseSize = new Size((Int32)((float)sourceImage.Width * percent), (Int32)((float)sourceImage.Height * percent));
}
StartImage = new Bitmap(baseSize.Width, baseSize.Height, sourceImage.PixelFormat);
StartImage.SetResolution(sourceImage.HorizontalResolution, sourceImage.VerticalResolution);
// Create the drawing object and white background
Graphics g = Graphics.FromImage(StartImage);
g.SmoothingMode = SmoothingMode.AntiAlias;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
g.DrawImage(sourceImage, new Rectangle(-1, -1, baseSize.Width + 1, baseSize.Height + 1), 0, 0, sourceImage.Width, sourceImage.Height, GraphicsUnit.Pixel);
g.Dispose();
// Locks the source image and copies it to the byte array and releases the source image
srcBitmapData = StartImage.LockBits(new Rectangle(0, 0, StartImage.Width, StartImage.Height), ImageLockMode.ReadOnly, StartImage.PixelFormat);
srcPixels = new byte[StartImage.Width * StartImage.Height * (Depth / 8)];
Marshal.Copy(srcBitmapData.Scan0, srcPixels, 0, srcPixels.Length);
StartImage.UnlockBits(srcBitmapData);
srcBitmapData = null;
// Create the target image byte array
dstPixels = new Byte[srcPixels.Length];
// Fill the entire frame with the selected background color
Int32 index = ((1 * StartImage.Width) + 1) * cCount; //index = ((Y * Width) + X) * cCount
do
{
if (Depth == 32) //For 32 bpp defines Red , Green, Blue and Alpha
{
dstPixels[index++] = backgroundColor.B;
dstPixels[index++] = backgroundColor.G;
dstPixels[index++] = backgroundColor.R;
dstPixels[index++] = backgroundColor.A; // a
}
if (Depth == 24) //For 24 bpp defines Red , Green and Blue
{
dstPixels[index++] = backgroundColor.B;
dstPixels[index++] = backgroundColor.G;
dstPixels[index++] = backgroundColor.R;
}
if (Depth == 8)
// For 8 bpp defines the value of color ( Red , Green and Blue to be the same thing)
{
dstPixels[index++] = backgroundColor.B;
}
} while (index < srcPixels.Length);
// Calculate the maximum possible extent for the image and multiply by the desired factor
double amp = 0;
double ang = Math.PI * 0.5;
for (Int32 a = 0; a < StartImage.Height; a++)
{
int y = (int)((StartImage.Height / 2) - amp * Math.Sin(ang));
if ((y < 0) || (y > StartImage.Height))
break;
amp = a;
}
amp = (amp - 2) * (factor < -1 ? -1 : (factor > 1 ? 1 : factor));
// Define variables that calculates the cutoff points (if any)
Int32 x1, y1, x2, y2;
x1 = StartImage.Width;
y1 = StartImage.Height;
x2 = 0;
y2 = 0;
// Copy pixel by pixel for the new positions
index = ((1 * StartImage.Width) + 1) * cCount;
do
{
Int32 y = (Int32)((index / cCount) / StartImage.Width);
Int32 x = (index / cCount) - (y * StartImage.Width);
Point pt = NewPoint(new Point(x, y), StartImage.Width, StartImage.Height, amp, factor < 0);
//Values ​​for crop
if (factor >= 0)
{
if (x == StartImage.Width / 2)
{
if (pt.Y < y1)
y1 = pt.Y;
if (pt.Y > y2)
y2 = pt.Y;
}
if (y == StartImage.Height / 2)
{
if (pt.X < x1)
x1 = pt.X;
if (pt.X > x2)
x2 = pt.X;
}
}
else
{
if ((x == 1) && (y == 1))
{
y1 = pt.Y;
x1 = pt.X;
}
if ((x == StartImage.Width - 1) && (y == StartImage.Height - 1))
{
y2 = pt.Y;
x2 = pt.X;
}
}
//Bytes Index which will apply the pixel
Int32 dstIndex = ((pt.Y * StartImage.Width) + pt.X) * cCount;
if (Depth == 32)
{
dstPixels[dstIndex] = srcPixels[index++];
dstPixels[dstIndex + 1] = srcPixels[index++];
dstPixels[dstIndex + 2] = srcPixels[index++];
dstPixels[dstIndex + 3] = srcPixels[index++]; // a
}
if (Depth == 24)
{
dstPixels[dstIndex] = srcPixels[index++];
dstPixels[dstIndex + 1] = srcPixels[index++];
dstPixels[dstIndex + 2] = srcPixels[index++];
}
if (Depth == 8)
{
dstPixels[dstIndex] = srcPixels[index++];
}
} while (index < srcPixels.Length);
//Creates a new image based on the byte array previously created
NewImage = new Bitmap(StartImage.Width, StartImage.Height, StartImage.PixelFormat);
NewImage.SetResolution(StartImage.HorizontalResolution, StartImage.VerticalResolution);
dstBitmapData = NewImage.LockBits(new Rectangle(0, 0, StartImage.Width, StartImage.Height), ImageLockMode.WriteOnly, StartImage.PixelFormat);
Marshal.Copy(dstPixels, 0, dstBitmapData.Scan0, dstPixels.Length);
NewImage.UnlockBits(dstBitmapData);
//Generates the final image to crop or resize the real coo
Bitmap FinalImage = new Bitmap(sourceImage.Width + 1, sourceImage.Height, StartImage.PixelFormat);
NewImage.SetResolution(StartImage.HorizontalResolution, StartImage.VerticalResolution);
Graphics g1 = Graphics.FromImage(FinalImage);
g1.SmoothingMode = SmoothingMode.AntiAlias;
g1.InterpolationMode = InterpolationMode.HighQualityBicubic;
g1.PixelOffsetMode = PixelOffsetMode.HighQuality;
//Performs the cut if enabled automatic cutting and there is need to cut
if ((autoCrop) && ((x1 > 0) || (y1 > 0) || (x2 < NewImage.Height) || (y2 < NewImage.Height)))
{
Rectangle cropRect = new Rectangle(x1, y1, x2 - x1, y2 - y1);
g1.DrawImage(NewImage, new Rectangle(-1, -1, FinalImage.Width + 1, FinalImage.Height + 1), cropRect.X, cropRect.Y, cropRect.Width, cropRect.Height, GraphicsUnit.Pixel);
}
else
{
g1.DrawImage(NewImage, new Rectangle(-1, -1, FinalImage.Width + 1, FinalImage.Height + 1), 0, 0, NewImage.Width, NewImage.Height, GraphicsUnit.Pixel);
}
g1.Dispose();
g1 = null;
NewImage = null;
FinalImage.Save("output.jpg");
FinalImage.Dispose();
}
finally
{
srcBitmapData = null;
srcPixels = null;
dstPixels = null;
dstBitmapData = null;
}
Such a distortion as a symmetry of revolution.
In polar coordinates, with the pole at the center of the image, it is expressed as
r' = f(r)
Θ' = Θ
where the quote indicates the distorted coordinates. The function f is unknown and should be measured empirically, by calibration (looking at a regular target).
To correct the image, you need to invert the function f and apply the reverse transform to the image. In fact, it is easier to measure g directly by calibration. As a starting approximation, a simple model like
r = r' + a.r'³
can do.
Most probably you don't have a picture of a grid taken with the same lens. Your last resort is to implement the undistortion function with adjustable parameters, and optimize these by trial and error.
It should also be possible to derive the calibration curve by looking at the deformation of straight lines, but this is more "technical".
In Cartesian coordinates, you can express the correction transform as
x = g(r').x'/r'
y = g(r').y'/r'
where r' = √x'²+y'².
Use the algorithm from here:
http://www.helviojunior.com.br/fotografia/barrel-and-pincushion-distortion/
It worked for me
I've made some revamp to the HelvioJunior's library (that was linked by #Tarek.Mh), I think this may suit your need:
Below, the code:
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Runtime.InteropServices;
using static System.Math;
namespace HelvioJunior
{
//https://www.helviojunior.com.br/fotografia/barrel-and-pincushion-distortion/
public class Program
{
private static void Main(string[] args)
{
Bitmap source = (Bitmap)Image.FromFile(#"JpwX0.png");
Bitmap bmp = BarrelDistortion(source, 4/10f, true);
bmp.Save(#"test.png");
bmp.Dispose();
source.Dispose();
}
static public Bitmap BarrelDistortion(Bitmap sourceImage, double factor = 0, bool autoCrop = true, uint previewRectangleWidth = 0, Color? fillerColor = null)
{
int sourceRight = sourceImage.Width - 1, sourceBottom = sourceImage.Height - 1;
// Vertical amplitude is half the height times factor
// Horizontal amplitude is missing ; vertical amplitude's applied to both directions
double amp = sourceBottom / 2f * factor;
// Inner shrinking area points
RePoint[] lPts;
bool inverse = factor < 0;
// Shrinking area coordinates (center point is considered always available)
double x1 = sourceRight / 2f,
y1 = sourceBottom / 2f,
x2 = sourceRight / 2f,
y2 = sourceBottom / 2f;
if (inverse)
{
lPts = new RePoint[]
{
new RePoint(0, 0),
new RePoint(0, sourceBottom),
new RePoint(sourceRight, sourceBottom),
new RePoint(sourceRight, 0)
};
}
else
{
lPts = new RePoint[]
{
new RePoint(sourceRight * 1 / 2f, 0),
new RePoint(0, sourceBottom * 1 / 2f),
new RePoint(sourceRight, sourceBottom * 1 / 2f),
new RePoint(sourceRight * 1 / 2f, sourceBottom)
};
}
foreach (var pN in lPts.Select(pt => NewPoint(pt, sourceImage.Width, sourceImage.Height, amp, inverse)))
{
if (pN.Y < y1) y1 = pN.Y;
if (pN.Y > y2) y2 = pN.Y;
if (pN.X < x1) x1 = pN.X;
if (pN.X > x2) x2 = pN.X;
}
// Bytes per color from bit per pixel (bpp) format
int bpcCount = Image.GetPixelFormatSize(sourceImage.PixelFormat) / 8;
Rectangle sourceRectangle = new Rectangle(0, 0, sourceImage.Width, sourceImage.Height);
int srcLength = sourceImage.Width * sourceImage.Height * bpcCount;
// Gets sourceImage byte array as srcpixels
BitmapData srcBitmapData = sourceImage.LockBits(sourceRectangle, ImageLockMode.ReadOnly, sourceImage.PixelFormat);
byte[] srcPixels = new byte[srcLength];
Marshal.Copy(srcBitmapData.Scan0, srcPixels, 0, srcLength);
sourceImage.UnlockBits(srcBitmapData);
srcBitmapData = null;
// Destination byte array preparation as dstPixels
byte[] dstPixels = new byte[srcLength];
int dstIndex = 0;
// Filler color preparation
Color fillColor = fillerColor ?? Color.Transparent;
if (!autoCrop)
{
if (bpcCount <= 4) // Depth > 32bpp may not work as expected, filler color's not applied for bit safety reason
do
{
dstPixels[dstIndex++] = fillColor.B;
if (bpcCount > 1)
{
dstPixels[dstIndex++] = fillColor.G;
dstPixels[dstIndex++] = fillColor.R;
if (bpcCount > 3)
dstPixels[dstIndex++] = fillColor.A; // a
}
} while (dstIndex < srcLength);
}
// Byte-to-byte copy (incl. Point transformation)
int index = 0, srcBpcLength = srcLength - bpcCount;
do
{
int comp = index / bpcCount; // comp yields the current "pixel" position
int y = comp / sourceImage.Width; // Each line is sourceImage.Width bytes wide
int x = comp - (y * sourceImage.Width); // Remaining (comp - lines) bytes is target column (ranges from 0 to width - 1)
// Destination "pixel"
RePoint pt = NewPoint(new RePoint(x, y), sourceImage.Width, sourceImage.Height, amp, inverse);
dstIndex = (((int)pt.Y * sourceImage.Width) + (int)pt.X) * bpcCount; // dstIndex++ overflows when |amp| >= 2
if (dstIndex >= 0 && dstIndex <= srcBpcLength)
for (int i = 0; i++ < bpcCount;)
dstPixels[dstIndex++] = srcPixels[index++];
else
index += bpcCount;
} while (index < srcLength);
srcPixels = null;
// Destination bytes application
BitmapData dstBitmapData = sourceImage.LockBits(sourceRectangle, ImageLockMode.WriteOnly, sourceImage.PixelFormat);
Marshal.Copy(dstPixels, 0, dstBitmapData.Scan0, srcLength);
sourceImage.UnlockBits(dstBitmapData);
dstBitmapData = null;
dstPixels = null;
// Final Image area
Rectangle cropRect = new Rectangle((int)Ceiling(x1), (int)Ceiling(y1), (int)Ceiling(x2 - x1), (int)Ceiling(y2 - y1));
Rectangle destRectangle = autoCrop ? cropRect : sourceRectangle;
// Final image preparation
Bitmap FinalImage = new Bitmap(destRectangle.Width, destRectangle.Height, sourceImage.PixelFormat);
FinalImage.SetResolution(sourceImage.HorizontalResolution, sourceImage.VerticalResolution);
Graphics g1 = Graphics.FromImage(FinalImage);
g1.DrawImage(sourceImage, -destRectangle.X, -destRectangle.Y);
// Previsualization rectangle
if (previewRectangleWidth > 0)
g1.DrawRectangle(new Pen(Color.Red, previewRectangleWidth), cropRect.X - 1, cropRect.Y - 1, cropRect.Width + previewRectangleWidth, cropRect.Height + previewRectangleWidth);
g1.Dispose();
g1 = null;
return FinalImage;
}
private static RePoint NewPoint(RePoint aP, double Width, double Height, double Amplitude, bool inverse)
{
double h = aP.Y / (Height - 1);
double w = aP.X / (Width - 1);
// Works ok for [0/2] to [1/2]
// Floating point error(s) here, in the range of ]1/2] to [2/2] (No workaround found)
double sinX = Round(Sin(PI * w), 15); // Range of [0] to [1] * PI ; result ranges from 0 (far from center) to 1 (at center)
double sinY = Round(Sin(PI * h), 15);
double caX = Amplitude * (1 - 2 * w);
double caY = Amplitude * (1 - 2 * h);
double aY = 0, aX = 0;
if (inverse)
{
aX = -caX;
aY = -caY;
}
double pY = aP.Y + aY + caY * sinX;
double pX = aP.X + aX + caX * sinY;
return new RePoint(pX, pY);
}
private struct RePoint
{
public double X;
public double Y;
public RePoint(double x, double y)
{
X = x;
Y = y;
}
}
}
}

Photo printing in C#

I have the following C# code to print 8x6 photos in a desktop application.
It works on regular printer with regular letter size paper.
But my client is using kodak printer with 8x6 paper, the photos are printing but their size is different, they are not printing in full 8x6 size, I'm doing something wrong.
Can someone please guide me in right direction.
public void Print(List ListToBePrinted)
{
PrintDialog SelectedPrinter = new PrintDialog();
if (SelectedPrinter.ShowDialog() == true)
{
PrintCapabilities printerCapabilities = SelectedPrinter.PrintQueue.GetPrintCapabilities();
Size PageSize = new Size(printerCapabilities.PageImageableArea.ExtentWidth, printerCapabilities.PageImageableArea.ExtentHeight);
Size PrintableImageSize = new Size();
foreach (Uri aUri in ListToBePrinted)
{
DrawingVisual drawVisual = new DrawingVisual();
ImageBrush imageBrush = new ImageBrush();
imageBrush.ImageSource = new BitmapImage(aUri);
imageBrush.Stretch = Stretch.Fill;
imageBrush.TileMode = TileMode.None;
imageBrush.AlignmentX = AlignmentX.Center;
imageBrush.AlignmentY = AlignmentY.Center;
if (imageBrush.ImageSource.Width > imageBrush.ImageSource.Height)
PrintableImageSize = new Size(768, 576); //8x6
else PrintableImageSize = new Size(576, 768); //6x8
double xcor = 0; double ycor = 0;
if (imageBrush.ImageSource.Width > imageBrush.ImageSource.Height)
{
if ((PageSize.Width - PrintableImageSize.Height) > 0)
xcor = (PageSize.Width - PrintableImageSize.Height) / 2;
if ((PageSize.Height - PrintableImageSize.Width) > 0)
ycor = (PageSize.Height - PrintableImageSize.Width) / 2;
}
else
{
if ((PageSize.Width - PrintableImageSize.Width) > 0)
xcor = (PageSize.Width - PrintableImageSize.Width) / 2;
if ((PageSize.Height - PrintableImageSize.Height) > 0)
ycor = (PageSize.Height - PrintableImageSize.Height) / 2;
}
using (DrawingContext drawingContext = drawVisual.RenderOpen())
{
if (imageBrush.ImageSource.Width > imageBrush.ImageSource.Height)
{
drawingContext.PushTransform(new RotateTransform(90, PrintableImageSize.Width / 2, PrintableImageSize.Height / 2));
}
drawingContext.DrawRectangle(imageBrush, null, new Rect(xcor, ycor, PrintableImageSize.Width, PrintableImageSize.Height));
}
SelectedPrinter.PrintVisual(drawVisual, "Print");
}
}
}
Checkout the HardMarginX and HardMarginY values, if you can find them.
I have this code in one of my apps (where e is a PrintPageEventArgs)
e.Graphics.DrawImage(nextImage, e.PageSettings.PrintableArea.X - e.PageSettings.HardMarginX, e.PageSettings.PrintableArea.Y - e.PageSettings.HardMarginY, e.PageSettings.Landscape ? e.PageSettings.PrintableArea.Height : e.PageSettings.PrintableArea.Width, e.PageSettings.Landscape ? e.PageSettings.PrintableArea.Width : e.PageSettings.PrintableArea.Height);
My printing function is a bit primitive, but maybe you can adjust your xcor and ycor based on the hard margins.

Categories