Elysia Tools
Navigation
C#
Windows Image Processing - C# Samples
Comprehensive C# image processing examples for Windows platform including image manipulation, filtering, format conversion, and advanced computer vision operations
Samples
Entries inside this sample collection
Basic Image Operations
Fundamental image operations including loading, saving, resizing, cropping, and basic pixel manipulation using System.Drawing
Difficulty
5/10
Estimated time
25 min
Tags
csharp, image-processing, graphics, windows
Prerequisites
C# basics, System.Drawing, Graphics concepts
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
class BasicImageOperations
{
// 1. Image Loading and Basic Information
public static void ImageLoadingExample()
{
Console.WriteLine("=== Image Loading Example ===");
try
{
// Create a simple test image programmatically
using (Bitmap bitmap = new Bitmap(400, 300))
{
using (Graphics graphics = Graphics.FromImage(bitmap))
{
// Fill background
graphics.Clear(Color.LightBlue);
// Draw some shapes
graphics.FillRectangle(Brushes.Red, 50, 50, 100, 80);
graphics.FillEllipse(Brushes.Green, 200, 100, 120, 120);
graphics.FillPolygon(Brushes.Yellow, new Point[] {
new Point(300, 50), new Point(350, 150), new Point(250, 150)
});
// Add text
graphics.DrawString("Test Image", new Font("Arial", 16), Brushes.Black, 150, 200);
}
// Display image information
Console.WriteLine($"Image Dimensions: {bitmap.Width} x {bitmap.Height}");
Console.WriteLine($"Pixel Format: {bitmap.PixelFormat}");
Console.WriteLine($"Horizontal Resolution: {bitmap.HorizontalResolution} DPI");
Console.WriteLine($"Vertical Resolution: {bitmap.VerticalResolution} DPI");
Console.WriteLine($"Physical Dimension: {bitmap.Size}");
// Save the image
bitmap.Save("test_image.png", ImageFormat.Png);
Console.WriteLine("\nTest image saved as: test_image.png");
// Get pixel information
Color centerPixel = bitmap.GetPixel(bitmap.Width / 2, bitmap.Height / 2);
Console.WriteLine($"\nCenter pixel color: R={centerPixel.R}, G={centerPixel.G}, B={centerPixel.B}");
}
}
catch (Exception ex)
{
Console.WriteLine($"Error creating image: {ex.Message}");
}
}
// 2. Image Resizing with Different Interpolation Modes
public static void ImageResizingExample()
{
Console.WriteLine("\n=== Image Resizing Example ===");
try
{
// Load or create source image
using (Bitmap sourceImage = new Bitmap(400, 300))
using (Graphics graphics = Graphics.FromImage(sourceImage))
{
// Create a gradient background
using (LinearGradientBrush brush = new LinearGradientBrush(
new Rectangle(0, 0, sourceImage.Width, sourceImage.Height),
Color.Blue, Color.White, LinearGradientMode.Vertical))
{
graphics.FillRectangle(brush, 0, 0, sourceImage.Width, sourceImage.Height);
}
// Add pattern
for (int x = 0; x < sourceImage.Width; x += 20)
{
for (int y = 0; y < sourceImage.Height; y += 20)
{
graphics.FillEllipse(Brushes.White, x, y, 10, 10);
}
}
sourceImage.Save("original_image.png", ImageFormat.Png);
Console.WriteLine($"Original image: {sourceImage.Width}x{sourceImage.Height}");
// Different interpolation modes for resizing
var interpolationModes = new[]
{
new { Mode = InterpolationMode.NearestNeighbor, Name = "NearestNeighbor" },
new { Mode = InterpolationMode.Bilinear, Name = "Bilinear" },
new { Mode = InterpolationMode.Bicubic, Name = "Bicubic" },
new { Mode = InterpolationMode.HighQualityBicubic, Name = "HighQualityBicubic" }
};
foreach (var interp in interpolationModes)
{
Bitmap resizedImage = ResizeImage(sourceImage, 200, 150, interp.Mode);
resizedImage.Save($"resized_{interp.Name.ToLower()}.png", ImageFormat.Png);
resizedImage.Dispose();
Console.WriteLine($"Resized with {interp.Name}: 200x150");
}
// Enlarge image
Bitmap enlargedImage = ResizeImage(sourceImage, 600, 450, InterpolationMode.HighQualityBicubic);
enlargedImage.Save("enlarged_image.png", ImageFormat.Png);
enlargedImage.Dispose();
Console.WriteLine("Enlarged image: 600x450");
}
}
catch (Exception ex)
{
Console.WriteLine($"Error resizing image: {ex.Message}");
}
}
// 3. Image Cropping and Rotation
public static void ImageCroppingAndRotationExample()
{
Console.WriteLine("\n=== Image Cropping and Rotation Example ===");
try
{
// Create a test image with clear orientation markers
using (Bitmap originalImage = new Bitmap(400, 300))
using (Graphics graphics = Graphics.FromImage(originalImage))
{
graphics.Clear(Color.White);
// Draw arrow pointing up
graphics.FillPolygon(Brushes.Red, new Point[] {
new Point(200, 50), new Point(180, 90), new Point(220, 90)
});
graphics.DrawString("UP", new Font("Arial", 14, FontStyle.Bold), Brushes.Black, 180, 100);
// Draw directional markers
graphics.DrawString("TOP", new Font("Arial", 12), Brushes.Blue, 170, 20);
graphics.DrawString("RIGHT", new Font("Arial", 12), Brushes.Green, 350, 145);
graphics.DrawString("BOTTOM", new Font("Arial", 12), Brushes.Blue, 160, 270);
graphics.DrawString("LEFT", new Font("Arial", 12), Brushes.Green, 10, 145);
originalImage.Save("orientation_original.png", ImageFormat.Png);
Console.WriteLine("Created orientation test image");
// Crop the image (center 200x200)
Rectangle cropRect = new Rectangle(100, 50, 200, 200);
using (Bitmap croppedImage = CropImage(originalImage, cropRect))
{
croppedImage.Save("cropped_image.png", ImageFormat.Png);
Console.WriteLine($"Cropped image: {croppedImage.Width}x{croppedImage.Height}");
}
// Rotate image
var rotations = new[]
{
new { Angle = 90f, Name = "90deg" },
new { Angle = 180f, Name = "180deg" },
new { Angle = 270f, Name = "270deg" }
};
foreach (var rotation in rotations)
{
using (Bitmap rotatedImage = RotateImage(originalImage, rotation.Angle))
{
rotatedImage.Save($"rotated_{rotation.Name}.png", ImageFormat.Png);
Console.WriteLine($"Rotated image {rotation.Name}: {rotatedImage.Width}x{rotatedImage.Height}");
}
}
// Custom rotation (45 degrees)
using (Bitmap customRotatedImage = RotateImage(originalImage, 45f))
{
customRotatedImage.Save("rotated_45deg.png", ImageFormat.Png);
Console.WriteLine($"Rotated image 45deg: {customRotatedImage.Width}x{customRotatedImage.Height}");
}
}
}
catch (Exception ex)
{
Console.WriteLine($"Error in cropping/rotation: {ex.Message}");
}
}
// 4. Image Format Conversion
public static void ImageFormatConversionExample()
{
Console.WriteLine("\n=== Image Format Conversion Example ===");
try
{
// Create a colorful test image
using (Bitmap originalImage = new Bitmap(300, 200))
using (Graphics graphics = Graphics.FromImage(originalImage))
{
// Create rainbow gradient
Color[] colors = { Color.Red, Color.Orange, Color.Yellow, Color.Green, Color.Blue, Color.Indigo, Color.Violet };
float step = 300f / colors.Length;
for (int i = 0; i < colors.Length; i++)
{
using (SolidBrush brush = new SolidBrush(colors[i]))
{
graphics.FillRectangle(brush, i * step, 0, step, 200);
}
}
// Add text overlay
graphics.DrawString("Format Conversion Test", new Font("Arial", 16, FontStyle.Bold), Brushes.White, 50, 80);
Console.WriteLine("Original image created");
// Convert to different formats
var formats = new[]
{
new { Format = ImageFormat.Png, Name = "png" },
new { Format = ImageFormat.Jpeg, Name = "jpg" },
new { Format = ImageFormat.Bmp, Name = "bmp" },
new { Format = ImageFormat.Gif, Name = "gif" },
new { Format = ImageFormat.Tiff, Name = "tiff" }
};
foreach (var format in formats)
{
string fileName = \"conversion_test.\" + format.Name;
originalImage.Save(fileName, format.Format);
FileInfo fileInfo = new FileInfo(fileName);
Console.WriteLine($"Converted to {format.Name.ToUpper()}: {fileInfo.Length:N0} bytes");
}
// Test JPEG quality settings
Console.WriteLine("\nJPEG Quality Comparison:");
var qualityLevels = new[] { 20, 50, 75, 90, 100 };
foreach (int quality in qualityLevels)
{
string fileName = $"jpeg_quality_{quality}.jpg";
SaveJpegWithQuality(originalImage, fileName, quality);
FileInfo fileInfo = new FileInfo(fileName);
Console.WriteLine($"Quality {quality}%: {fileInfo.Length:N0} bytes");
}
}
}
catch (Exception ex)
{
Console.WriteLine($"Error in format conversion: {ex.Message}");
}
}
// 5. Basic Image Filters
public static void BasicImageFiltersExample()
{
Console.WriteLine("\n=== Basic Image Filters Example ===");
try
{
// Create a test image
using (Bitmap originalImage = CreateTestImage(400, 300))
{
originalImage.Save("filter_original.png", ImageFormat.Png);
Console.WriteLine("Original test image created");
// Apply grayscale filter
using (Bitmap grayscaleImage = ApplyGrayscaleFilter(originalImage))
{
grayscaleImage.Save("filter_grayscale.png", ImageFormat.Png);
Console.WriteLine("Grayscale filter applied");
}
// Apply sepia filter
using (Bitmap sepiaImage = ApplySepiaFilter(originalImage))
{
sepiaImage.Save("filter_sepia.png", ImageFormat.Png);
Console.WriteLine("Sepia filter applied");
}
// Apply invert filter
using (Bitmap invertedImage = ApplyInvertFilter(originalImage))
{
invertedImage.Save("filter_invert.png", ImageFormat.Png);
Console.WriteLine("Invert filter applied");
}
// Apply brightness adjustment
using (Bitmap brightImage = AdjustBrightness(originalImage, 50))
{
brightImage.Save("filter_bright.png", ImageFormat.Png);
Console.WriteLine("Brightness increased by 50");
}
// Apply contrast adjustment
using (Bitmap contrastImage = AdjustContrast(originalImage, 1.5f))
{
contrastImage.Save("filter_contrast.png", ImageFormat.Png);
Console.WriteLine("Contrast increased by 50%");
}
// Apply blur filter (simple box blur)
using (Bitmap blurredImage = ApplyBlurFilter(originalImage, 5))
{
blurredImage.Save("filter_blur.png", ImageFormat.Png);
Console.WriteLine("Blur filter applied (radius 5)");
}
}
}
catch (Exception ex)
{
Console.WriteLine($"Error applying filters: {ex.Message}");
}
}
// 6. Image Comparison and Analysis
public static void ImageAnalysisExample()
{
Console.WriteLine("\n=== Image Analysis Example ===");
try
{
// Create two similar test images
using (Bitmap image1 = CreateTestImage(200, 150))
using (Bitmap image2 = CreateModifiedTestImage(200, 150))
{
image1.Save("analysis_image1.png", ImageFormat.Png);
image2.Save("analysis_image2.png", ImageFormat.Png);
Console.WriteLine("Created two test images for comparison");
// Basic image statistics
AnalyzeImage(image1, "Image 1");
AnalyzeImage(image2, "Image 2");
// Compare images
double difference = CompareImages(image1, image2);
Console.WriteLine($"\nImage difference: {difference:F2}%");
// Find different pixels
int differentPixels = CountDifferentPixels(image1, image2);
Console.WriteLine($"Different pixels: {differentPixels:N0} out of {image1.Width * image1.Height:N0}");
// Calculate histogram
Console.WriteLine("\nColor Histogram:");
CalculateHistogram(image1);
}
}
catch (Exception ex)
{
Console.WriteLine($"Error in image analysis: {ex.Message}");
}
}
// Helper methods
private static Bitmap ResizeImage(Bitmap source, int width, int height, InterpolationMode interpolationMode)
{
Bitmap resized = new Bitmap(width, height);
using (Graphics graphics = Graphics.FromImage(resized))
{
graphics.InterpolationMode = interpolationMode;
graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
graphics.CompositingQuality = CompositingQuality.HighQuality;
graphics.DrawImage(source, 0, 0, width, height);
}
return resized;
}
private static Bitmap CropImage(Bitmap source, Rectangle cropRect)
{
Bitmap cropped = new Bitmap(cropRect.Width, cropRect.Height);
using (Graphics graphics = Graphics.FromImage(cropped))
{
graphics.DrawImage(source, 0, 0, cropRect, GraphicsUnit.Pixel);
}
return cropped;
}
private static Bitmap RotateImage(Bitmap source, float angle)
{
// Create rotated rectangle
PointF[] rotationPoints = new PointF[]
{
new PointF(0, 0),
new PointF(source.Width, 0),
new PointF(0, source.Height)
};
using (Matrix rotationMatrix = new Matrix())
{
rotationMatrix.Rotate(angle);
rotationMatrix.TransformPoints(rotationPoints);
RectangleF boundingBox = new RectangleF(
Math.Min(Math.Min(rotationPoints[0].X, rotationPoints[1].X), rotationPoints[2].X),
Math.Min(Math.Min(rotationPoints[0].Y, rotationPoints[1].Y), rotationPoints[2].Y),
Math.Max(Math.Max(rotationPoints[0].X, rotationPoints[1].X), rotationPoints[2].X) -
Math.Min(Math.Min(rotationPoints[0].X, rotationPoints[1].X), rotationPoints[2].X),
Math.Max(Math.Max(rotationPoints[0].Y, rotationPoints[1].Y), rotationPoints[2].Y) -
Math.Min(Math.Min(rotationPoints[0].Y, rotationPoints[1].Y), rotationPoints[2].Y));
Bitmap rotated = new Bitmap((int)Math.Ceiling(boundingBox.Width), (int)Math.Ceiling(boundingBox.Height));
using (Graphics graphics = Graphics.FromImage(rotated))
{
graphics.TranslateTransform(boundingBox.Width / 2, boundingBox.Height / 2);
graphics.RotateTransform(angle);
graphics.TranslateTransform(-source.Width / 2, -source.Height / 2);
graphics.DrawImage(source, 0, 0);
}
return rotated;
}
}
private static void SaveJpegWithQuality(Bitmap image, string fileName, int quality)
{
EncoderParameters encoderParams = new EncoderParameters(1);
encoderParams.Param[0] = new EncoderParameter(Encoder.Quality, quality);
ImageCodecInfo jpegCodec = GetEncoderInfo(ImageFormat.Jpeg);
image.Save(fileName, jpegCodec, encoderParams);
}
private static ImageCodecInfo GetEncoderInfo(ImageFormat format)
{
ImageCodecInfo[] codecs = ImageCodecInfo.GetImageDecoders();
foreach (ImageCodecInfo codec in codecs)
{
if (codec.FormatID == format.Guid)
{
return codec;
}
}
return null;
}
private static Bitmap CreateTestImage(int width, int height)
{
Bitmap bitmap = new Bitmap(width, height);
using (Graphics graphics = Graphics.FromImage(bitmap))
{
// Gradient background
using (LinearGradientBrush brush = new LinearGradientBrush(
new Rectangle(0, 0, width, height), Color.Blue, Color.Yellow, LinearGradientMode.Horizontal))
{
graphics.FillRectangle(brush, 0, 0, width, height);
}
// Add some shapes
graphics.FillEllipse(Brushes.Red, width/4, height/4, width/2, height/2);
graphics.FillRectangle(Brushes.Green, width/3, height/3, width/3, height/3);
}
return bitmap;
}
private static Bitmap CreateModifiedTestImage(int width, int height)
{
Bitmap bitmap = CreateTestImage(width, height);
using (Graphics graphics = Graphics.FromImage(bitmap))
{
// Add modification
graphics.FillRectangle(Brushes.White, width/2 - 20, height/2 - 20, 40, 40);
}
return bitmap;
}
private static Bitmap ApplyGrayscaleFilter(Bitmap source)
{
Bitmap result = new Bitmap(source.Width, source.Height);
for (int y = 0; y < source.Height; y++)
{
for (int x = 0; x < source.Width; x++)
{
Color pixel = source.GetPixel(x, y);
int gray = (int)(pixel.R * 0.299 + pixel.G * 0.587 + pixel.B * 0.114);
result.SetPixel(x, y, Color.FromArgb(gray, gray, gray));
}
}
return result;
}
private static Bitmap ApplySepiaFilter(Bitmap source)
{
Bitmap result = new Bitmap(source.Width, source.Height);
for (int y = 0; y < source.Height; y++)
{
for (int x = 0; x < source.Width; x++)
{
Color pixel = source.GetPixel(x, y);
int r = Math.Min(255, (int)(pixel.R * 0.393 + pixel.G * 0.769 + pixel.B * 0.189));
int g = Math.Min(255, (int)(pixel.R * 0.349 + pixel.G * 0.686 + pixel.B * 0.168));
int b = Math.Min(255, (int)(pixel.R * 0.272 + pixel.G * 0.534 + pixel.B * 0.131));
result.SetPixel(x, y, Color.FromArgb(r, g, b));
}
}
return result;
}
private static Bitmap ApplyInvertFilter(Bitmap source)
{
Bitmap result = new Bitmap(source.Width, source.Height);
for (int y = 0; y < source.Height; y++)
{
for (int x = 0; x < source.Width; x++)
{
Color pixel = source.GetPixel(x, y);
result.SetPixel(x, y, Color.FromArgb(255 - pixel.R, 255 - pixel.G, 255 - pixel.B));
}
}
return result;
}
private static Bitmap AdjustBrightness(Bitmap source, int brightness)
{
Bitmap result = new Bitmap(source.Width, source.Height);
for (int y = 0; y < source.Height; y++)
{
for (int x = 0; x < source.Width; x++)
{
Color pixel = source.GetPixel(x, y);
int r = Math.Min(255, Math.Max(0, pixel.R + brightness));
int g = Math.Min(255, Math.Max(0, pixel.G + brightness));
int b = Math.Min(255, Math.Max(0, pixel.B + brightness));
result.SetPixel(x, y, Color.FromArgb(r, g, b));
}
}
return result;
}
private static Bitmap AdjustContrast(Bitmap source, float contrast)
{
Bitmap result = new Bitmap(source.Width, source.Height);
for (int y = 0; y < source.Height; y++)
{
for (int x = 0; x < source.Width; x++)
{
Color pixel = source.GetPixel(x, y);
int r = Math.Min(255, Math.Max(0, (int)(((pixel.R / 255.0 - 0.5) * contrast + 0.5) * 255)));
int g = Math.Min(255, Math.Max(0, (int)(((pixel.G / 255.0 - 0.5) * contrast + 0.5) * 255)));
int b = Math.Min(255, Math.Max(0, (int)(((pixel.B / 255.0 - 0.5) * contrast + 0.5) * 255)));
result.SetPixel(x, y, Color.FromArgb(r, g, b));
}
}
return result;
}
private static Bitmap ApplyBlurFilter(Bitmap source, int radius)
{
Bitmap result = new Bitmap(source.Width, source.Height);
// Simple box blur implementation
for (int y = radius; y < source.Height - radius; y++)
{
for (int x = radius; x < source.Width - radius; x++)
{
int r = 0, g = 0, b = 0;
int count = 0;
for (int dy = -radius; dy <= radius; dy++)
{
for (int dx = -radius; dx <= radius; dx++)
{
Color pixel = source.GetPixel(x + dx, y + dy);
r += pixel.R;
g += pixel.G;
b += pixel.B;
count++;
}
}
result.SetPixel(x, y, Color.FromArgb(r / count, g / count, b / count));
}
}
return result;
}
private static void AnalyzeImage(Bitmap image, string imageName)
{
Console.WriteLine($"\n{imageName} Analysis:");
Console.WriteLine($" Dimensions: {image.Width} x {image.Height}");
Console.WriteLine($" Total Pixels: {image.Width * image.Height:N0}");
// Calculate average color
long totalR = 0, totalG = 0, totalB = 0;
for (int y = 0; y < Math.Min(image.Height, 100); y++) // Sample first 100 rows
{
for (int x = 0; x < image.Width; x++)
{
Color pixel = image.GetPixel(x, y);
totalR += pixel.R;
totalG += pixel.G;
totalB += pixel.B;
}
}
int sampleSize = Math.Min(100, image.Height) * image.Width;
Console.WriteLine($" Average Color (sample): R={totalR / sampleSize}, G={totalG / sampleSize}, B={totalB / sampleSize}");
}
private static double CompareImages(Bitmap image1, Bitmap image2)
{
if (image1.Width != image2.Width || image1.Height != image2.Height)
return 100.0;
long totalDifference = 0;
long totalPixels = image1.Width * image1.Height;
for (int y = 0; y < image1.Height; y++)
{
for (int x = 0; x < image1.Width; x++)
{
Color pixel1 = image1.GetPixel(x, y);
Color pixel2 = image2.GetPixel(x, y);
int diff = Math.Abs(pixel1.R - pixel2.R) +
Math.Abs(pixel1.G - pixel2.G) +
Math.Abs(pixel1.B - pixel2.B);
totalDifference += diff;
}
}
return (totalDifference / (double)totalPixels / 3.0) * 100.0; // Convert to percentage
}
private static int CountDifferentPixels(Bitmap image1, Bitmap image2)
{
if (image1.Width != image2.Width || image1.Height != image2.Height)
return image1.Width * image1.Height;
int differentPixels = 0;
for (int y = 0; y < image1.Height; y++)
{
for (int x = 0; x < image1.Width; x++)
{
Color pixel1 = image1.GetPixel(x, y);
Color pixel2 = image2.GetPixel(x, y);
if (pixel1 != pixel2)
differentPixels++;
}
}
return differentPixels;
}
private static void CalculateHistogram(Bitmap image)
{
int[] redHistogram = new int[256];
int[] greenHistogram = new int[256];
int[] blueHistogram = new int[256];
// Sample pixels (every 10th pixel for performance)
for (int y = 0; y < image.Height; y += 10)
{
for (int x = 0; x < image.Width; x += 10)
{
Color pixel = image.GetPixel(x, y);
redHistogram[pixel.R]++;
greenHistogram[pixel.G]++;
blueHistogram[pixel.B]++;
}
}
// Find peaks
int redPeak = Array.IndexOf(redHistogram, redHistogram.Max());
int greenPeak = Array.IndexOf(greenHistogram, greenHistogram.Max());
int bluePeak = Array.IndexOf(blueHistogram, blueHistogram.Max());
Console.WriteLine($" Red peak: {redPeak}");
Console.WriteLine($" Green peak: {greenPeak}");
Console.WriteLine($" Blue peak: {bluePeak}");
}
public static void RunAllExamples()
{
Console.WriteLine("Basic Image Processing Examples");
Console.WriteLine("=================================");
ImageLoadingExample();
ImageResizingExample();
ImageCroppingAndRotationExample();
ImageFormatConversionExample();
BasicImageFiltersExample();
ImageAnalysisExample();
Console.WriteLine("\nBasic image processing examples completed!");
}
}Advanced Image Processing
Advanced image processing techniques including convolution filters, edge detection, morphological operations, and image enhancement algorithms
Difficulty
8/10
Estimated time
35 min
Tags
csharp, image-processing, computer-vision, filters, windows
Prerequisites
C# intermediate, Image processing concepts, Linear algebra basics
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
class AdvancedImageProcessing
{
// 1. Convolution Filters
public static void ConvolutionFiltersExample()
{
Console.WriteLine("=== Convolution Filters Example ===");
try
{
// Create test image with patterns
using (Bitmap originalImage = CreateTestPatternImage(400, 300))
{
originalImage.Save("convolution_original.png", ImageFormat.Png);
Console.WriteLine("Created test pattern image");
// Define convolution kernels
var kernels = new[]
{
new { Name = "Sharpen", Kernel = new double[,] {
{ 0, -1, 0 },
{ -1, 5, -1 },
{ 0, -1, 0 }
}, Factor = 1.0, Offset = 0 },
new { Name = "Edge_Detect", Kernel = new double[,] {
{ -1, -1, -1 },
{ -1, 8, -1 },
{ -1, -1, -1 }
}, Factor = 1.0, Offset = 0 },
new { Name = "Emboss", Kernel = new double[,] {
{ -2, -1, 0 },
{ -1, 1, 1 },
{ 0, 1, 2 }
}, Factor = 1.0, Offset = 0 },
new { Name = "Gaussian_Blur", Kernel = CreateGaussianKernel(5, 1.0), Factor = 1.0, Offset = 0 }
};
foreach (var kernelInfo in kernels)
{
using (Bitmap filteredImage = ApplyConvolutionFilter(originalImage, kernelInfo.Kernel, kernelInfo.Factor, kernelInfo.Offset))
{
string fileName = $"convolution_{kernelInfo.Name.ToLower().Replace('_', '_')}.png";
filteredImage.Save(fileName, ImageFormat.Png);
Console.WriteLine($"Applied {kernelInfo.Name} filter: {fileName}");
}
}
// Custom Sobel edge detection
using (Bitmap sobelImage = ApplySobelEdgeDetection(originalImage))
{
sobelImage.Save("convolution_sobel.png", ImageFormat.Png);
Console.WriteLine("Applied Sobel edge detection");
}
}
}
catch (Exception ex)
{
Console.WriteLine($"Error in convolution filters: {ex.Message}");
}
}
// 2. Morphological Operations
public static void MorphologicalOperationsExample()
{
Console.WriteLine("\n=== Morphological Operations Example ===");
try
{
// Create binary test image
using (Bitmap binaryImage = CreateBinaryTestImage(400, 300))
{
binaryImage.Save("morphology_original.png", ImageFormat.Png);
Console.WriteLine("Created binary test image");
// Erosion
using (Bitmap erodedImage = ApplyErosion(binaryImage, 3))
{
erodedImage.Save("morphology_erosion.png", ImageFormat.Png);
Console.WriteLine("Applied erosion operation");
}
// Dilation
using (Bitmap dilatedImage = ApplyDilation(binaryImage, 3))
{
dilatedImage.Save("morphology_dilation.png", ImageFormat.Png);
Console.WriteLine("Applied dilation operation");
}
// Opening (Erosion followed by Dilation)
using (Bitmap openedImage = ApplyOpening(binaryImage, 3))
{
openedImage.Save("morphology_opening.png", ImageFormat.Png);
Console.WriteLine("Applied opening operation");
}
// Closing (Dilation followed by Erosion)
using (Bitmap closedImage = ApplyClosing(binaryImage, 3))
{
closedImage.Save("morphology_closing.png", ImageFormat.Png);
Console.WriteLine("Applied closing operation");
}
}
}
catch (Exception ex)
{
Console.WriteLine($"Error in morphological operations: {ex.Message}");
}
}
// 3. Image Enhancement
public static void ImageEnhancementExample()
{
Console.WriteLine("\n=== Image Enhancement Example ===");
try
{
// Create low-quality test image
using (Bitmap lowQualityImage = CreateLowQualityTestImage(400, 300))
{
lowQualityImage.Save("enhancement_original.png", ImageFormat.Png);
Console.WriteLine("Created low-quality test image");
// Histogram equalization
using (Bitmap equalizedImage = ApplyHistogramEqualization(lowQualityImage))
{
equalizedImage.Save("enhancement_histogram_equalization.png", ImageFormat.Png);
Console.WriteLine("Applied histogram equalization");
}
// Gamma correction
using (Bitmap gammaCorrectedImage = ApplyGammaCorrection(lowQualityImage, 1.5))
{
gammaCorrectedImage.Save("enhancement_gamma.png", ImageFormat.Png);
Console.WriteLine("Applied gamma correction (gamma = 1.5)");
}
// Noise reduction (median filter)
using (Bitmap denoisedImage = ApplyMedianFilter(lowQualityImage, 3))
{
denoisedImage.Save("enhancement_median_filter.png", ImageFormat.Png);
Console.WriteLine("Applied median filter for noise reduction");
}
// Unsharp masking for sharpening
using (Bitmap sharpenedImage = ApplyUnsharpMask(lowQualityImage, 1.5, 1.0))
{
sharpenedImage.Save("enhancement_unsharp_mask.png", ImageFormat.Png);
Console.WriteLine("Applied unsharp masking for sharpening");
}
}
}
catch (Exception ex)
{
Console.WriteLine($"Error in image enhancement: {ex.Message}");
}
}
// 4. Color Space Operations
public static void ColorSpaceOperationsExample()
{
Console.WriteLine("\n=== Color Space Operations Example ===");
try
{
// Create colorful test image
using (Bitmap originalImage = CreateColorfulTestImage(400, 300))
{
originalImage.Save("color_original.png", ImageFormat.Png);
Console.WriteLine("Created colorful test image");
// Convert to grayscale using different methods
using (Bitmap averageGray = ConvertToGrayscaleAverage(originalImage))
{
averageGray.Save("color_grayscale_average.png", ImageFormat.Png);
Console.WriteLine("Converted to grayscale (average method)");
}
using (Bitmap luminanceGray = ConvertToGrayscaleLuminance(originalImage))
{
luminanceGray.Save("color_grayscale_luminance.png", ImageFormat.Png);
Console.WriteLine("Converted to grayscale (luminance method)");
}
// Color channel extraction
ExtractColorChannels(originalImage, "color_channel");
// HSV color space operations
using (Bitmap hsvImage = ConvertToHSV(originalImage))
{
hsvImage.Save("color_hsv.png", ImageFormat.Png);
Console.WriteLine("Converted to HSV color space");
}
// Color balance adjustment
using (Bitmap balancedImage = AdjustColorBalance(originalImage, 1.2, 0.8, 1.1))
{
balancedImage.Save("color_balanced.png", ImageFormat.Png);
Console.WriteLine("Adjusted color balance (R:1.2, G:0.8, B:1.1)");
}
// Saturation adjustment
using (Bitmap saturatedImage = AdjustSaturation(originalImage, 1.5))
{
saturatedImage.Save("color_saturated.png", ImageFormat.Png);
Console.WriteLine("Increased saturation by 50%");
}
}
}
catch (Exception ex)
{
Console.WriteLine($"Error in color space operations: {ex.Message}");
}
}
// 5. Feature Detection
public static void FeatureDetectionExample()
{
Console.WriteLine("\n=== Feature Detection Example ===");
try
{
// Create image with geometric features
using (Bitmap featureImage = CreateFeatureTestImage(400, 300))
{
featureImage.Save("feature_original.png", ImageFormat.Png);
Console.WriteLine("Created feature test image");
// Corner detection (Harris-like)
using (Bitmap cornerImage = DetectCorners(featureImage, 50))
{
cornerImage.Save("feature_corners.png", ImageFormat.Png);
Console.WriteLine("Detected corners in the image");
}
// Blob detection
using (Bitmap blobImage = DetectBlobs(featureImage, 20))
{
blobImage.Save("feature_blobs.png", ImageFormat.Png);
Console.WriteLine("Detected blobs in the image");
}
// Line detection using Hough transform (simplified)
using (Bitmap lineImage = DetectLines(featureImage))
{
lineImage.Save("feature_lines.png", ImageFormat.Png);
Console.WriteLine("Detected lines in the image");
}
// Connected components analysis
using (Bitmap componentsImage = FindConnectedComponents(featureImage))
{
componentsImage.Save("feature_components.png", ImageFormat.Png);
Console.WriteLine("Found connected components");
}
}
}
catch (Exception ex)
{
Console.WriteLine($"Error in feature detection: {ex.Message}");
}
}
// Helper methods for convolution and filtering
private static double[,] CreateGaussianKernel(int size, double sigma)
{
double[,] kernel = new double[size, size];
double sum = 0;
int center = size / 2;
for (int y = 0; y < size; y++)
{
for (int x = 0; x < size; x++)
{
double exponent = -(Math.Pow(x - center, 2) + Math.Pow(y - center, 2)) / (2 * sigma * sigma);
kernel[y, x] = Math.Exp(exponent);
sum += kernel[y, x];
}
}
// Normalize
for (int y = 0; y < size; y++)
{
for (int x = 0; x < size; x++)
{
kernel[y, x] /= sum;
}
}
return kernel;
}
private static Bitmap ApplyConvolutionFilter(Bitmap source, double[,] kernel, double factor, double offset)
{
Bitmap result = new Bitmap(source.Width, source.Height);
int kernelWidth = kernel.GetLength(1);
int kernelHeight = kernel.GetLength(0);
int kernelRadiusX = kernelWidth / 2;
int kernelRadiusY = kernelHeight / 2;
for (int y = kernelRadiusY; y < source.Height - kernelRadiusY; y++)
{
for (int x = kernelRadiusX; x < source.Width - kernelRadiusX; x++)
{
double red = 0, green = 0, blue = 0;
for (int ky = -kernelRadiusY; ky <= kernelRadiusY; ky++)
{
for (int kx = -kernelRadiusX; kx <= kernelRadiusX; kx++)
{
Color pixel = source.GetPixel(x + kx, y + ky);
double kernelValue = kernel[ky + kernelRadiusY, kx + kernelRadiusX];
red += pixel.R * kernelValue;
green += pixel.G * kernelValue;
blue += pixel.B * kernelValue;
}
}
// Apply factor and offset
red = Math.Min(255, Math.Max(0, red * factor + offset));
green = Math.Min(255, Math.Max(0, green * factor + offset));
blue = Math.Min(255, Math.Max(0, blue * factor + offset));
result.SetPixel(x, y, Color.FromArgb((int)red, (int)green, (int)blue));
}
}
return result;
}
private static Bitmap ApplySobelEdgeDetection(Bitmap source)
{
// Sobel operators
double[,] sobelX = { { -1, 0, 1 }, { -2, 0, 2 }, { -1, 0, 1 } };
double[,] sobelY = { { -1, -2, -1 }, { 0, 0, 0 }, { 1, 2, 1 } };
Bitmap result = new Bitmap(source.Width, source.Height);
for (int y = 1; y < source.Height - 1; y++)
{
for (int x = 1; x < source.Width - 1; x++)
{
double gx = 0, gy = 0;
for (int ky = -1; ky <= 1; ky++)
{
for (int kx = -1; kx <= 1; kx++)
{
Color pixel = source.GetPixel(x + kx, y + ky);
double gray = pixel.R * 0.299 + pixel.G * 0.587 + pixel.B * 0.114;
gx += gray * sobelX[ky + 1, kx + 1];
gy += gray * sobelY[ky + 1, kx + 1];
}
}
double magnitude = Math.Sqrt(gx * gx + gy * gy);
int edgeValue = Math.Min(255, (int)magnitude);
result.SetPixel(x, y, Color.FromArgb(edgeValue, edgeValue, edgeValue));
}
}
return result;
}
// Morphological operations
private static Bitmap ApplyErosion(Bitmap source, int kernelSize)
{
Bitmap result = new Bitmap(source.Width, source.Height);
int radius = kernelSize / 2;
for (int y = radius; y < source.Height - radius; y++)
{
for (int x = radius; x < source.Width - radius; x++)
{
byte minPixel = 255;
for (int ky = -radius; ky <= radius; ky++)
{
for (int kx = -radius; kx <= radius; kx++)
{
Color pixel = source.GetPixel(x + kx, y + ky);
byte gray = (byte)(pixel.R * 0.299 + pixel.G * 0.587 + pixel.B * 0.114);
minPixel = Math.Min(minPixel, gray);
}
}
Color newColor = Color.FromArgb(minPixel, minPixel, minPixel);
result.SetPixel(x, y, newColor);
}
}
return result;
}
private static Bitmap ApplyDilation(Bitmap source, int kernelSize)
{
Bitmap result = new Bitmap(source.Width, source.Height);
int radius = kernelSize / 2;
for (int y = radius; y < source.Height - radius; y++)
{
for (int x = radius; x < source.Width - radius; x++)
{
byte maxPixel = 0;
for (int ky = -radius; ky <= radius; ky++)
{
for (int kx = -radius; kx <= radius; kx++)
{
Color pixel = source.GetPixel(x + kx, y + ky);
byte gray = (byte)(pixel.R * 0.299 + pixel.G * 0.587 + pixel.B * 0.114);
maxPixel = Math.Max(maxPixel, gray);
}
}
Color newColor = Color.FromArgb(maxPixel, maxPixel, maxPixel);
result.SetPixel(x, y, newColor);
}
}
return result;
}
private static Bitmap ApplyOpening(Bitmap source, int kernelSize)
{
Bitmap eroded = ApplyErosion(source, kernelSize);
Bitmap result = ApplyDilation(eroded, kernelSize);
eroded.Dispose();
return result;
}
private static Bitmap ApplyClosing(Bitmap source, int kernelSize)
{
Bitmap dilated = ApplyDilation(source, kernelSize);
Bitmap result = ApplyErosion(dilated, kernelSize);
dilated.Dispose();
return result;
}
// Image enhancement methods
private static Bitmap ApplyHistogramEqualization(Bitmap source)
{
// Calculate histogram
int[] histogram = new int[256];
for (int y = 0; y < source.Height; y++)
{
for (int x = 0; x < source.Width; x++)
{
Color pixel = source.GetPixel(x, y);
byte gray = (byte)(pixel.R * 0.299 + pixel.G * 0.587 + pixel.B * 0.114);
histogram[gray]++;
}
}
// Calculate cumulative distribution
int[] cdf = new int[256];
cdf[0] = histogram[0];
for (int i = 1; i < 256; i++)
{
cdf[i] = cdf[i - 1] + histogram[i];
}
// Create lookup table
byte[] lut = new byte[256];
int totalPixels = source.Width * source.Height;
for (int i = 0; i < 256; i++)
{
lut[i] = (byte)(255.0 * cdf[i] / totalPixels + 0.5);
}
// Apply lookup table
Bitmap result = new Bitmap(source.Width, source.Height);
for (int y = 0; y < source.Height; y++)
{
for (int x = 0; x < source.Width; x++)
{
Color pixel = source.GetPixel(x, y);
byte gray = (byte)(pixel.R * 0.299 + pixel.G * 0.587 + pixel.B * 0.114);
byte equalized = lut[gray];
result.SetPixel(x, y, Color.FromArgb(equalized, equalized, equalized));
}
}
return result;
}
private static Bitmap ApplyGammaCorrection(Bitmap source, double gamma)
{
Bitmap result = new Bitmap(source.Width, source.Height);
// Create gamma lookup table
byte[] gammaTable = new byte[256];
for (int i = 0; i < 256; i++)
{
gammaTable[i] = (byte)(255 * Math.Pow(i / 255.0, 1.0 / gamma) + 0.5);
}
for (int y = 0; y < source.Height; y++)
{
for (int x = 0; x < source.Width; x++)
{
Color pixel = source.GetPixel(x, y);
Color correctedPixel = Color.FromArgb(
gammaTable[pixel.R],
gammaTable[pixel.G],
gammaTable[pixel.B]
);
result.SetPixel(x, y, correctedPixel);
}
}
return result;
}
private static Bitmap ApplyMedianFilter(Bitmap source, int kernelSize)
{
Bitmap result = new Bitmap(source.Width, source.Height);
int radius = kernelSize / 2;
for (int y = radius; y < source.Height - radius; y++)
{
for (int x = radius; x < source.Width - radius; x++)
{
var redValues = new byte[kernelSize * kernelSize];
var greenValues = new byte[kernelSize * kernelSize];
var blueValues = new byte[kernelSize * kernelSize];
int index = 0;
for (int ky = -radius; ky <= radius; ky++)
{
for (int kx = -radius; kx <= radius; kx++)
{
Color pixel = source.GetPixel(x + kx, y + ky);
redValues[index] = pixel.R;
greenValues[index] = pixel.G;
blueValues[index] = pixel.B;
index++;
}
}
Array.Sort(redValues);
Array.Sort(greenValues);
Array.Sort(blueValues);
int medianIndex = kernelSize * kernelSize / 2;
result.SetPixel(x, y, Color.FromArgb(
redValues[medianIndex],
greenValues[medianIndex],
blueValues[medianIndex]
));
}
}
return result;
}
private static Bitmap ApplyUnsharpMask(Bitmap source, double amount, double radius)
{
// Create Gaussian blur
double[,] gaussianKernel = CreateGaussianKernel((int)(radius * 3) | 1, radius);
Bitmap blurred = ApplyConvolutionFilter(source, gaussianKernel, 1.0, 0);
// Apply unsharp mask
Bitmap result = new Bitmap(source.Width, source.Height);
for (int y = 0; y < source.Height; y++)
{
for (int x = 0; x < source.Width; x++)
{
Color original = source.GetPixel(x, y);
Color blurredPixel = blurred.GetPixel(x, y);
int r = Math.Min(255, Math.Max(0, (int)(original.R + amount * (original.R - blurredPixel.R))));
int g = Math.Min(255, Math.Max(0, (int)(original.G + amount * (original.G - blurredPixel.G))));
int b = Math.Min(255, Math.Max(0, (int)(original.B + amount * (original.B - blurredPixel.B))));
result.SetPixel(x, y, Color.FromArgb(r, g, b));
}
}
blurred.Dispose();
return result;
}
// Color space conversion methods
private static Bitmap ConvertToGrayscaleAverage(Bitmap source)
{
Bitmap result = new Bitmap(source.Width, source.Height);
for (int y = 0; y < source.Height; y++)
{
for (int x = 0; x < source.Width; x++)
{
Color pixel = source.GetPixel(x, y);
byte gray = (byte)((pixel.R + pixel.G + pixel.B) / 3);
result.SetPixel(x, y, Color.FromArgb(gray, gray, gray));
}
}
return result;
}
private static Bitmap ConvertToGrayscaleLuminance(Bitmap source)
{
Bitmap result = new Bitmap(source.Width, source.Height);
for (int y = 0; y < source.Height; y++)
{
for (int x = 0; x < source.Width; x++)
{
Color pixel = source.GetPixel(x, y);
byte gray = (byte)(0.299 * pixel.R + 0.587 * pixel.G + 0.114 * pixel.B);
result.SetPixel(x, y, Color.FromArgb(gray, gray, gray));
}
}
return result;
}
private static void ExtractColorChannels(Bitmap source, string prefix)
{
Bitmap redChannel = new Bitmap(source.Width, source.Height);
Bitmap greenChannel = new Bitmap(source.Width, source.Height);
Bitmap blueChannel = new Bitmap(source.Width, source.Height);
for (int y = 0; y < source.Height; y++)
{
for (int x = 0; x < source.Width; x++)
{
Color pixel = source.GetPixel(x, y);
redChannel.SetPixel(x, y, Color.FromArgb(pixel.R, pixel.R, pixel.R));
greenChannel.SetPixel(x, y, Color.FromArgb(pixel.G, pixel.G, pixel.G));
blueChannel.SetPixel(x, y, Color.FromArgb(pixel.B, pixel.B, pixel.B));
}
}
redChannel.Save(prefix + "_red.png", ImageFormat.Png);
greenChannel.Save(prefix + "_green.png", ImageFormat.Png);
blueChannel.Save(prefix + "_blue.png", ImageFormat.Png);
redChannel.Dispose();
greenChannel.Dispose();
blueChannel.Dispose();
}
private static Bitmap ConvertToHSV(Bitmap source)
{
Bitmap result = new Bitmap(source.Width, source.Height);
for (int y = 0; y < source.Height; y++)
{
for (int x = 0; x < source.Width; x++)
{
Color pixel = source.GetPixel(x, y);
// Simple HSV-like transformation for demonstration
double h = pixel.GetHue() / 360.0;
double s = pixel.GetSaturation();
double v = pixel.GetBrightness();
int r = (int)(h * 255);
int g = (int)(s * 255);
int b = (int)(v * 255);
result.SetPixel(x, y, Color.FromArgb(r, g, b));
}
}
return result;
}
private static Bitmap AdjustColorBalance(Bitmap source, double redFactor, double greenFactor, double blueFactor)
{
Bitmap result = new Bitmap(source.Width, source.Height);
for (int y = 0; y < source.Height; y++)
{
for (int x = 0; x < source.Width; x++)
{
Color pixel = source.GetPixel(x, y);
int r = Math.Min(255, Math.Max(0, (int)(pixel.R * redFactor)));
int g = Math.Min(255, Math.Max(0, (int)(pixel.G * greenFactor)));
int b = Math.Min(255, Math.Max(0, (int)(pixel.B * blueFactor)));
result.SetPixel(x, y, Color.FromArgb(r, g, b));
}
}
return result;
}
private static Bitmap AdjustSaturation(Bitmap source, double saturation)
{
Bitmap result = new Bitmap(source.Width, source.Height);
for (int y = 0; y < source.Height; y++)
{
for (int x = 0; x < source.Width; x++)
{
Color pixel = source.GetPixel(x, y);
double gray = 0.299 * pixel.R + 0.587 * pixel.G + 0.114 * pixel.B;
int r = Math.Min(255, Math.Max(0, (int)(gray + saturation * (pixel.R - gray))));
int g = Math.Min(255, Math.Max(0, (int)(gray + saturation * (pixel.G - gray))));
int b = Math.Min(255, Math.Max(0, (int)(gray + saturation * (pixel.B - gray))));
result.SetPixel(x, y, Color.FromArgb(r, g, b));
}
}
return result;
}
// Feature detection methods
private static Bitmap DetectCorners(Bitmap source, int threshold)
{
Bitmap result = new Bitmap(source.Width, source.Height);
// Copy original image
for (int y = 0; y < source.Height; y++)
{
for (int x = 0; x < source.Width; x++)
{
result.SetPixel(x, y, source.GetPixel(x, y));
}
}
// Simple corner detection (simplified Harris corner detector)
for (int y = 1; y < source.Height - 1; y++)
{
for (int x = 1; x < source.Width - 1; x++)
{
// Calculate gradients
double gx = 0, gy = 0;
for (int dy = -1; dy <= 1; dy++)
{
for (int dx = -1; dx <= 1; dx++)
{
Color pixel = source.GetPixel(x + dx, y + dy);
double gray = pixel.R * 0.299 + pixel.G * 0.587 + pixel.B * 0.114;
gx += gray * dx;
gy += gray * dy;
}
}
double cornerStrength = Math.Sqrt(gx * gx + gy * gy);
if (cornerStrength > threshold)
{
// Mark corner with red
for (int dy = -2; dy <= 2; dy++)
{
for (int dx = -2; dx <= 2; dx++)
{
if (x + dx >= 0 && x + dx < result.Width && y + dy >= 0 && y + dy < result.Height)
{
result.SetPixel(x + dx, y + dy, Color.Red);
}
}
}
}
}
}
return result;
}
private static Bitmap DetectBlobs(Bitmap source, int minSize)
{
Bitmap result = new Bitmap(source.Width, source.Height);
// Convert to binary
bool[,] binary = new bool[source.Width, source.Height];
for (int y = 0; y < source.Height; y++)
{
for (int x = 0; x < source.Width; x++)
{
Color pixel = source.GetPixel(x, y);
double gray = pixel.R * 0.299 + pixel.G * 0.587 + pixel.B * 0.114;
binary[x, y] = gray > 128;
}
}
// Find connected components
bool[,] visited = new bool[source.Width, source.Height];
Random rand = new Random();
for (int y = 0; y < source.Height; y++)
{
for (int x = 0; x < source.Width; x++)
{
if (binary[x, y] && !visited[x, y])
{
// Find size of connected component
int size = 0;
var component = new System.Collections.Generic.Queue<Point>();
component.Enqueue(new Point(x, y));
visited[x, y] = true;
while (component.Count > 0)
{
Point p = component.Dequeue();
size++;
// Check neighbors
for (int dy = -1; dy <= 1; dy++)
{
for (int dx = -1; dx <= 1; dx++)
{
int nx = p.X + dx;
int ny = p.Y + dy;
if (nx >= 0 && nx < source.Width && ny >= 0 && ny < source.Height &&
binary[nx, ny] && !visited[nx, ny])
{
visited[nx, ny] = true;
component.Enqueue(new Point(nx, ny));
}
}
}
}
// Color component if it meets size threshold
if (size >= minSize)
{
Color blobColor = Color.FromArgb(rand.Next(256), rand.Next(256), rand.Next(256));
// Re-traverse component to color it
component.Clear();
component.Enqueue(new Point(x, y));
visited[x, y] = false; // Reset for this component
while (component.Count > 0)
{
Point p = component.Dequeue();
result.SetPixel(p.X, p.Y, blobColor);
for (int dy = -1; dy <= 1; dy++)
{
for (int dx = -1; dx <= 1; dx++)
{
int nx = p.X + dx;
int ny = p.Y + dy;
if (nx >= 0 && nx < source.Width && ny >= 0 && ny < source.Height &&
binary[nx, ny] && visited[nx, ny])
{
visited[nx, ny] = false;
component.Enqueue(new Point(nx, ny));
}
}
}
}
}
}
}
}
return result;
}
private static Bitmap DetectLines(Bitmap source)
{
// Simplified line detection
Bitmap result = new Bitmap(source.Width, source.Height);
// Copy original
for (int y = 0; y < source.Height; y++)
{
for (int x = 0; x < source.Width; x++)
{
result.SetPixel(x, y, source.GetPixel(x, y));
}
}
// Detect horizontal and vertical lines
for (int y = 1; y < source.Height - 1; y++)
{
for (int x = 1; x < source.Width - 1; x++)
{
Color pixel = source.GetPixel(x, y);
double gray = pixel.R * 0.299 + pixel.G * 0.587 + pixel.B * 0.114;
// Check for horizontal line
bool horizontalLine = true;
for (int dx = -5; dx <= 5; dx++)
{
if (x + dx >= 0 && x + dx < source.Width)
{
Color neighborPixel = source.GetPixel(x + dx, y);
double neighborGray = neighborPixel.R * 0.299 + neighborPixel.G * 0.587 + neighborPixel.B * 0.114;
if (Math.Abs(gray - neighborGray) > 50)
{
horizontalLine = false;
break;
}
}
}
// Check for vertical line
bool verticalLine = true;
for (int dy = -5; dy <= 5; dy++)
{
if (y + dy >= 0 && y + dy < source.Height)
{
Color neighborPixel = source.GetPixel(x, y + dy);
double neighborGray = neighborPixel.R * 0.299 + neighborPixel.G * 0.587 + neighborPixel.B * 0.114;
if (Math.Abs(gray - neighborGray) > 50)
{
verticalLine = false;
break;
}
}
}
if (horizontalLine || verticalLine)
{
result.SetPixel(x, y, Color.Yellow);
}
}
}
return result;
}
private static Bitmap FindConnectedComponents(Bitmap source)
{
return DetectBlobs(source, 10); // Reuse blob detection with smaller threshold
}
// Test image creation methods
private static Bitmap CreateTestPatternImage(int width, int height)
{
Bitmap bitmap = new Bitmap(width, height);
using (Graphics graphics = Graphics.FromImage(bitmap))
{
graphics.Clear(Color.White);
// Create various patterns
for (int y = 0; y < height; y += 20)
{
for (int x = 0; x < width; x += 20)
{
if ((x / 20 + y / 20) % 2 == 0)
{
graphics.FillRectangle(Brushes.Black, x, y, 20, 20);
}
}
}
// Add some circles and lines
graphics.DrawEllipse(Pens.Red, 50, 50, 100, 100);
graphics.DrawRectangle(Pens.Blue, 200, 100, 150, 80);
graphics.DrawLine(Pens.Green, 0, 0, width, height);
graphics.DrawLine(Pens.Green, width, 0, 0, height);
}
return bitmap;
}
private static Bitmap CreateBinaryTestImage(int width, int height)
{
Bitmap bitmap = new Bitmap(width, height);
using (Graphics graphics = Graphics.FromImage(bitmap))
{
graphics.Clear(Color.White);
// Create binary patterns
graphics.FillRectangle(Brushes.Black, 50, 50, 100, 100);
graphics.FillRectangle(Brushes.Black, 200, 80, 80, 80);
graphics.FillEllipse(Brushes.Black, 300, 150, 60, 60);
// Add some noise
Random rand = new Random();
for (int i = 0; i < 500; i++)
{
int x = rand.Next(width);
int y = rand.Next(height);
graphics.FillEllipse(rand.Next(2) == 0 ? Brushes.Black : Brushes.White, x, y, 2, 2);
}
}
return bitmap;
}
private static Bitmap CreateLowQualityTestImage(int width, int height)
{
Bitmap bitmap = new Bitmap(width, height);
using (Graphics graphics = Graphics.FromImage(bitmap))
{
// Create low contrast image
graphics.Clear(Color.Gray);
// Add gradient with low contrast
for (int x = 0; x < width; x++)
{
int grayValue = 120 + (int)(20 * Math.Sin(x * 0.05));
using (SolidBrush brush = new SolidBrush(Color.FromArgb(grayValue, grayValue, grayValue)))
{
graphics.FillRectangle(brush, x, 0, 1, height);
}
}
// Add some shapes with similar colors
graphics.FillRectangle(Brushes.DarkGray, 50, 50, 100, 100);
graphics.FillEllipse(Brushes.LightGray, 200, 100, 80, 80);
}
// Add noise
Random rand = new Random();
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
Color pixel = bitmap.GetPixel(x, y);
int noise = rand.Next(-20, 21);
int newGray = Math.Min(255, Math.Max(0, pixel.R + noise));
bitmap.SetPixel(x, y, Color.FromArgb(newGray, newGray, newGray));
}
}
return bitmap;
}
private static Bitmap CreateColorfulTestImage(int width, int height)
{
Bitmap bitmap = new Bitmap(width, height);
using (Graphics graphics = Graphics.FromImage(bitmap))
{
// Create color gradient
using (LinearGradientBrush brush = new LinearGradientBrush(
new Rectangle(0, 0, width, height),
Color.Red, Color.Blue, LinearGradientMode.Diagonal))
{
graphics.FillRectangle(brush, 0, 0, width, height);
}
// Add colorful shapes
graphics.FillEllipse(Brushes.Yellow, 50, 50, 100, 100);
graphics.FillRectangle(Brushes.Green, 200, 100, 120, 80);
graphics.FillPolygon(Brushes.Magenta, new Point[] {
new Point(300, 200), new Point(350, 250), new Point(250, 250)
});
}
return bitmap;
}
private static Bitmap CreateFeatureTestImage(int width, int height)
{
Bitmap bitmap = new Bitmap(width, height);
using (Graphics graphics = Graphics.FromImage(bitmap))
{
graphics.Clear(Color.White);
// Add corners
graphics.FillRectangle(Brushes.Black, 50, 50, 10, 10);
graphics.FillRectangle(Brushes.Black, 100, 150, 10, 10);
graphics.FillRectangle(Brushes.Black, 200, 80, 10, 10);
// Add lines
graphics.DrawLine(Pens.Black, 150, 0, 150, height);
graphics.DrawLine(Pens.Black, 0, 200, width, 200);
graphics.DrawLine(Pens.Black, 0, 0, width, height);
// Add circles (blobs)
graphics.FillEllipse(Brushes.Black, 250, 50, 30, 30);
graphics.FillEllipse(Brushes.Black, 300, 150, 20, 20);
graphics.FillEllipse(Brushes.Black, 100, 220, 25, 25);
// Add connected components
graphics.FillRectangle(Brushes.Gray, 320, 220, 50, 50);
graphics.FillEllipse(Brushes.Gray, 330, 230, 30, 30);
}
return bitmap;
}
public static void RunAllExamples()
{
Console.WriteLine("Advanced Image Processing Examples");
Console.WriteLine("===================================");
ConvolutionFiltersExample();
MorphologicalOperationsExample();
ImageEnhancementExample();
ColorSpaceOperationsExample();
FeatureDetectionExample();
Console.WriteLine("\nAdvanced image processing examples completed!");
}
}Image Format Conversion and Optimization
Complete image format conversion system with quality optimization, metadata handling, and batch processing capabilities
Difficulty
7/10
Estimated time
30 min
Tags
csharp, image-processing, format-conversion, optimization, windows
Prerequisites
C# intermediate, Image processing, File I/O
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
using System.Collections.Generic;
using System.Linq;
class ImageFormatConversion
{
// 1. Basic Format Conversion
public static void BasicFormatConversionExample()
{
Console.WriteLine("=== Basic Format Conversion Example ===");
try
{
// Create a sample image
using (Bitmap sourceImage = CreateSampleImage(400, 300))
{
sourceImage.Save("conversion_source.png", ImageFormat.Png);
Console.WriteLine("Created source image: conversion_source.png");
// Supported formats for conversion
var formats = new[]
{
new { Name = "PNG", Format = ImageFormat.Png, Extension = ".png" },
new { Name = "JPEG", Format = ImageFormat.Jpeg, Extension = ".jpg" },
new { Name = "BMP", Format = ImageFormat.Bmp, Extension = ".bmp" },
new { Name = "GIF", Format = ImageFormat.Gif, Extension = ".gif" },
new { Name = "TIFF", Format = ImageFormat.Tiff, Extension = ".tiff" },
new { Name = "ICO", Format = ImageFormat.Icon, Extension = ".ico" }
};
foreach (var format in formats)
{
try
{
string outputFileName = $"converted_{format.Name.ToLower()}{format.Extension}";
sourceImage.Save(outputFileName, format.Format);
FileInfo fileInfo = new FileInfo(outputFileName);
Console.WriteLine($"Converted to {format.Name}: {fileInfo.Length:N0} bytes");
}
catch (Exception ex)
{
Console.WriteLine($"Failed to convert to {format.Name}: {ex.Message}");
}
}
}
}
catch (Exception ex)
{
Console.WriteLine($"Error in format conversion: {ex.Message}");
}
}
// 2. Quality Optimization for JPEG
public static void JPEGQualityOptimizationExample()
{
Console.WriteLine("\n=== JPEG Quality Optimization Example ===");
try
{
using (Bitmap sourceImage = CreateDetailedSampleImage(600, 400))
{
sourceImage.Save("quality_source.png", ImageFormat.Png);
Console.WriteLine("Created detailed source image");
// Test different quality levels
var qualityLevels = new[]
{
new { Quality = 10, Description = "Very Low" },
new { Quality = 25, Description = "Low" },
new { Quality = 50, Description = "Medium" },
new { Quality = 75, Description = "High" },
new { Quality = 90, Description = "Very High" },
new { Quality = 100, Description = "Maximum" }
};
Console.WriteLine("\nJPEG Quality Comparison:");
Console.WriteLine("Quality\tSize (KB)\tDescription");
foreach (var level in qualityLevels)
{
string fileName = $"jpeg_q{level.Quality:D3}.jpg";
SaveJPEGWithQuality(sourceImage, fileName, level.Quality);
FileInfo fileInfo = new FileInfo(fileName);
double sizeKB = fileInfo.Length / 1024.0;
Console.WriteLine($"{level.Quality:D3}\t{sizeKB:F1}\t\t{level.Description}");
}
// Calculate compression ratios
FileInfo originalInfo = new FileInfo("quality_source.png");
long originalSize = originalInfo.Length;
Console.WriteLine($"\nOriginal PNG size: {originalSize / 1024.0:F1} KB");
Console.WriteLine("JPEG Compression Ratios:");
foreach (var level in qualityLevels)
{
string fileName = $"jpeg_q{level.Quality:D3}.jpg";
FileInfo jpegInfo = new FileInfo(fileName);
double ratio = (double)originalSize / jpegInfo.Length;
Console.WriteLine($"Quality {level.Quality:D3}: {ratio:F1}:1 compression");
}
}
}
catch (Exception ex)
{
Console.WriteLine($"Error in quality optimization: {ex.Message}");
}
}
// 3. Batch Image Processing
public static void BatchProcessingExample()
{
Console.WriteLine("\n=== Batch Processing Example ===");
try
{
// Create a directory for batch processing
string batchDir = "batch_images";
Directory.CreateDirectory(batchDir);
// Create sample images
List<string> createdFiles = new List<string>();
for (int i = 1; i <= 5; i++)
{
using (Bitmap img = CreateNumberedImage(300, 200, i))
{
string fileName = Path.Combine(batchDir, $"image_{i:D2}.png");
img.Save(fileName, ImageFormat.Png);
createdFiles.Add(fileName);
}
}
Console.WriteLine($"Created {createdFiles.Count} sample images in {batchDir}");
// Batch resize
Console.WriteLine("\nBatch resizing to 150x100...");
BatchResizeImages(createdFiles, "resized_", 150, 100);
// Batch convert to JPEG with quality 75
Console.WriteLine("Batch converting to JPEG (quality 75)...");
BatchConvertToJPEG(createdFiles, "jpg_q75_", 75);
// Batch create thumbnails
Console.WriteLine("Batch creating thumbnails (64x64)...");
BatchCreateThumbnails(createdFiles, "thumb_", 64, 64);
// Process results
Console.WriteLine("\nBatch processing results:");
foreach (string file in createdFiles)
{
FileInfo original = new FileInfo(file);
Console.WriteLine($"Original: {original.Name} - {original.Length / 1024.0:F1} KB");
// Check resized version
string resizedFile = Path.Combine(batchDir, "resized_" + Path.GetFileName(file).Replace(".png", ".jpg"));
if (File.Exists(resizedFile))
{
FileInfo resized = new FileInfo(resizedFile);
Console.WriteLine($" Resized: {resized.Name} - {resized.Length / 1024.0:F1} KB");
}
// Check thumbnail
string thumbFile = Path.Combine(batchDir, "thumb_" + Path.GetFileName(file).Replace(".png", ".jpg"));
if (File.Exists(thumbFile))
{
FileInfo thumb = new FileInfo(thumbFile);
Console.WriteLine($" Thumbnail: {thumb.Name} - {thumb.Length / 1024.0:F1} KB");
}
}
Console.WriteLine($"\nBatch processing completed in {batchDir}");
}
catch (Exception ex)
{
Console.WriteLine($"Error in batch processing: {ex.Message}");
}
}
// 4. Image Metadata Handling
public static void MetadataHandlingExample()
{
Console.WriteLine("\n=== Image Metadata Handling Example ===");
try
{
// Create image with metadata
using (Bitmap image = CreateSampleImageWithMetadata(400, 300))
{
image.Save("metadata_source.jpg", ImageFormat.Jpeg);
Console.WriteLine("Created image with basic metadata");
// Read image properties
ReadImageProperties("metadata_source.jpg");
// Add custom metadata
AddCustomMetadata("metadata_source.jpg", "metadata_custom.jpg");
// Read enhanced metadata
ReadEnhancedMetadata("metadata_custom.jpg");
// Create image with EXIF data
CreateImageWithEXIFData("exif_test.jpg");
ReadEXIFData("exif_test.jpg");
}
}
catch (Exception ex)
{
Console.WriteLine($"Error in metadata handling: {ex.Message}");
}
}
// 5. Advanced Format Optimization
public static void AdvancedOptimizationExample()
{
Console.WriteLine("\n=== Advanced Format Optimization Example ===");
try
{
// Create test image with different content types
using (Bitmap photoImage = CreatePhotographTestImage(600, 400))
using (Bitmap graphicImage = CreateGraphicTestImage(600, 400))
using (Bitmap textImage = CreateTextTestImage(600, 400))
{
Console.WriteLine("Created test images: photo, graphic, and text");
// Optimize for photographs (JPEG)
OptimizeForPhotographs(photoImage, "optimized_photo");
// Optimize for graphics (PNG)
OptimizeForGraphics(graphicImage, "optimized_graphic");
// Optimize for text/images (PNG with compression)
OptimizeForText(textImage, "optimized_text");
// Compare file sizes
Console.WriteLine("\nOptimization Results:");
CompareOptimizationResults("photo", 600, 400);
CompareOptimizationResults("graphic", 600, 400);
CompareOptimizationResults("text", 600, 400);
}
// Multi-format optimization
Console.WriteLine("\n=== Multi-Format Optimization ===");
OptimizeForMultipleFormats("multi_opt_test", 400, 300);
}
catch (Exception ex)
{
Console.WriteLine($"Error in advanced optimization: {ex.Message}");
}
}
// 6. Image Analysis and Format Selection
public static void IntelligentFormatSelectionExample()
{
Console.WriteLine("\n=== Intelligent Format Selection Example ===");
try
{
// Test different image types
var testImages = new[]
{
new { Name = "photograph", Creator = (Func<Bitmap>)(() => CreatePhotographTestImage(300, 200)) },
new { Name = "screenshot", Creator = (Func<Bitmap>)(() => CreateScreenshotTestImage(300, 200)) },
new { Name = "logo", Creator = (Func<Bitmap>)(() => CreateLogoTestImage(300, 200)) },
new { Name = "chart", Creator = (Func<Bitmap>)(() => CreateChartTestImage(300, 200)) }
};
foreach (var testImage in testImages)
{
using (Bitmap image = testImage.Creator())
{
Console.WriteLine($"\nAnalyzing {testImage.Name} image:");
// Analyze image characteristics
var analysis = AnalyzeImageCharacteristics(image);
Console.WriteLine($" Colors: {analysis.ColorCount:N0}");
Console.WriteLine($" Unique colors: {analysis.UniqueColors:N0}");
Console.WriteLine($" Has transparency: {analysis.HasTransparency}");
Console.WriteLine($" Estimated detail level: {analysis.DetailLevel:F2}");
Console.WriteLine($" Image type: {analysis.ImageType}");
// Recommend format
string recommendedFormat = RecommendOptimalFormat(analysis);
Console.WriteLine($" Recommended format: {recommendedFormat}");
// Save with recommended format
string fileName = $"intelligent_{testImage.Name}.{recommendedFormat.ToLower()}";
SaveWithRecommendedFormat(image, fileName, recommendedFormat);
if (File.Exists(fileName))
{
FileInfo info = new FileInfo(fileName);
Console.WriteLine($" File size: {info.Length / 1024.0:F1} KB");
}
}
}
}
catch (Exception ex)
{
Console.WriteLine($"Error in intelligent format selection: {ex.Message}");
}
}
// Helper methods
private static void SaveJPEGWithQuality(Bitmap image, string fileName, int quality)
{
EncoderParameters encoderParams = new EncoderParameters(1);
encoderParams.Param[0] = new EncoderParameter(Encoder.Quality, quality);
ImageCodecInfo jpegCodec = GetEncoderInfo(ImageFormat.Jpeg);
image.Save(fileName, jpegCodec, encoderParams);
}
private static ImageCodecInfo GetEncoderInfo(ImageFormat format)
{
ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders();
foreach (ImageCodecInfo codec in codecs)
{
if (codec.FormatID == format.Guid)
{
return codec;
}
}
return null;
}
private static Bitmap CreateSampleImage(int width, int height)
{
Bitmap bitmap = new Bitmap(width, height);
using (Graphics graphics = Graphics.FromImage(bitmap))
{
graphics.Clear(Color.White);
// Create gradient background
using (LinearGradientBrush brush = new LinearGradientBrush(
new Rectangle(0, 0, width, height),
Color.LightBlue, Color.LightYellow, LinearGradientMode.Vertical))
{
graphics.FillRectangle(brush, 0, 0, width, height);
}
// Add some shapes
graphics.FillEllipse(Brushes.Red, width/4, height/4, width/2, height/2);
graphics.FillRectangle(Brushes.Green, width/3, height/3, width/3, height/3);
graphics.DrawString("Sample Image", new Font("Arial", 16), Brushes.Black, width/2 - 50, height/2 - 10);
}
return bitmap;
}
private static Bitmap CreateDetailedSampleImage(int width, int height)
{
Bitmap bitmap = new Bitmap(width, height);
using (Graphics graphics = Graphics.FromImage(bitmap))
{
graphics.Clear(Color.White);
// Create detailed pattern
Random rand = new Random(42); // Fixed seed for consistency
for (int y = 0; y < height; y += 2)
{
for (int x = 0; x < width; x += 2)
{
Color color = Color.FromArgb(
rand.Next(256),
rand.Next(256),
rand.Next(256));
graphics.FillRectangle(new SolidBrush(color), x, y, 2, 2);
}
}
// Add some gradients
for (int i = 0; i < 10; i++)
{
using (LinearGradientBrush brush = new LinearGradientBrush(
new Rectangle(i * 40, i * 20, 100, 100),
Color.FromArgb(rand.Next(256), rand.Next(256), rand.Next(256)),
Color.FromArgb(rand.Next(256), rand.Next(256), rand.Next(256)),
LinearGradientMode.Horizontal))
{
graphics.FillRectangle(brush, i * 40, i * 20, 100, 100);
}
}
}
return bitmap;
}
private static Bitmap CreateNumberedImage(int width, int height, int number)
{
Bitmap bitmap = new Bitmap(width, height);
using (Graphics graphics = Graphics.FromImage(bitmap))
{
// Random background color
Random rand = new Random(number);
Color bgColor = Color.FromArgb(rand.Next(128, 256), rand.Next(128, 256), rand.Next(128, 256));
graphics.Clear(bgColor);
// Draw number
using (Font font = new Font("Arial", 48, FontStyle.Bold))
{
graphics.DrawString(number.ToString(), font, Brushes.Black, width/2 - 30, height/2 - 30);
}
// Add some decorations
graphics.DrawEllipse(Pens.Black, 10, 10, width - 20, height - 20);
}
return bitmap;
}
private static void BatchResizeImages(List<string> files, string prefix, int width, int height)
{
foreach (string file in files)
{
try
{
using (Bitmap original = new Bitmap(file))
using (Bitmap resized = ResizeImage(original, width, height, true))
{
string directory = Path.GetDirectoryName(file);
string fileName = Path.GetFileNameWithoutExtension(file);
string outputFile = Path.Combine(directory, prefix + fileName + ".jpg");
SaveJPEGWithQuality(resized, outputFile, 85);
}
}
catch (Exception ex)
{
Console.WriteLine($"Error resizing {Path.GetFileName(file)}: {ex.Message}");
}
}
}
private static void BatchConvertToJPEG(List<string> files, string prefix, int quality)
{
foreach (string file in files)
{
try
{
using (Bitmap original = new Bitmap(file))
{
string directory = Path.GetDirectoryName(file);
string fileName = Path.GetFileNameWithoutExtension(file);
string outputFile = Path.Combine(directory, prefix + fileName + ".jpg");
SaveJPEGWithQuality(original, outputFile, quality);
}
}
catch (Exception ex)
{
Console.WriteLine($"Error converting {Path.GetFileName(file)}: {ex.Message}");
}
}
}
private static void BatchCreateThumbnails(List<string> files, string prefix, int width, int height)
{
foreach (string file in files)
{
try
{
using (Bitmap original = new Bitmap(file))
using (Bitmap thumbnail = CreateThumbnail(original, width, height))
{
string directory = Path.GetDirectoryName(file);
string fileName = Path.GetFileNameWithoutExtension(file);
string outputFile = Path.Combine(directory, prefix + fileName + ".jpg");
SaveJPEGWithQuality(thumbnail, outputFile, 90);
}
}
catch (Exception ex)
{
Console.WriteLine($"Error creating thumbnail for {Path.GetFileName(file)}: {ex.Message}");
}
}
}
private static Bitmap ResizeImage(Bitmap source, int width, int height, bool maintainAspectRatio)
{
if (maintainAspectRatio)
{
int sourceWidth = source.Width;
int sourceHeight = source.Height;
float aspectRatio = (float)sourceWidth / sourceHeight;
if (width / (float)height > aspectRatio)
{
width = (int)(height * aspectRatio);
}
else
{
height = (int)(width / aspectRatio);
}
}
Bitmap result = new Bitmap(width, height);
using (Graphics graphics = Graphics.FromImage(result))
{
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
graphics.CompositingQuality = CompositingQuality.HighQuality;
graphics.DrawImage(source, 0, 0, width, height);
}
return result;
}
private static Bitmap CreateThumbnail(Bitmap source, int width, int height)
{
// Crop to center and resize
int sourceWidth = source.Width;
int sourceHeight = source.Height;
int sourceX = 0, sourceY = 0;
int sourceCropWidth = sourceWidth;
int sourceCropHeight = sourceHeight;
float sourceAspect = (float)sourceWidth / sourceHeight;
float targetAspect = (float)width / height;
if (sourceAspect > targetAspect)
{
// Source is wider
sourceCropWidth = (int)(sourceHeight * targetAspect);
sourceX = (sourceWidth - sourceCropWidth) / 2;
}
else
{
// Source is taller
sourceCropHeight = (int)(sourceWidth / targetAspect);
sourceY = (sourceHeight - sourceCropHeight) / 2;
}
Bitmap result = new Bitmap(width, height);
using (Graphics graphics = Graphics.FromImage(result))
{
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.DrawImage(source,
new Rectangle(0, 0, width, height),
new Rectangle(sourceX, sourceY, sourceCropWidth, sourceCropHeight),
GraphicsUnit.Pixel);
}
return result;
}
// Metadata handling methods
private static void ReadImageProperties(string fileName)
{
try
{
using (Image image = Image.FromFile(fileName))
{
Console.WriteLine($"\nBasic properties for {Path.GetFileName(fileName)}:");
Console.WriteLine($" Width: {image.Width}px");
Console.WriteLine($" Height: {image.Height}px");
Console.WriteLine($" Pixel format: {image.PixelFormat}");
Console.WriteLine($" Horizontal resolution: {image.HorizontalResolution} DPI");
Console.WriteLine($" Vertical resolution: {image.VerticalResolution} DPI");
foreach (PropertyItem prop in image.PropertyItems)
{
Console.WriteLine($" Property ID: {prop.Id}, Type: {prop.Type}, Length: {prop.Len}");
}
}
}
catch (Exception ex)
{
Console.WriteLine($"Error reading properties: {ex.Message}");
}
}
private static void AddCustomMetadata(string sourceFile, string outputFile)
{
try
{
using (Image image = Image.FromFile(sourceFile))
{
// Add custom properties
PropertyItem titleProp = CreatePropertyItem(0x010E, "Sample Image Title");
PropertyItem authorProp = CreatePropertyItem(0x013B, "C# Image Processor");
PropertyItem commentProp = CreatePropertyItem(0x9286, "This is a test image with custom metadata");
image.SetPropertyItem(titleProp);
image.SetPropertyItem(authorProp);
image.SetPropertyItem(commentProp);
image.Save(outputFile, ImageFormat.Jpeg);
Console.WriteLine($"Added custom metadata to {outputFile}");
}
}
catch (Exception ex)
{
Console.WriteLine($"Error adding metadata: {ex.Message}");
}
}
private static PropertyItem CreatePropertyItem(int id, string value)
{
PropertyItem prop = (PropertyItem)System.Runtime.Serialization.FormatterServices.GetUninitializedObject(typeof(PropertyItem));
prop.Id = id;
prop.Type = 2; // ASCII
prop.Value = System.Text.Encoding.ASCII.GetBytes(value + "\0");
prop.Len = prop.Value.Length;
return prop;
}
private static void ReadEnhancedMetadata(string fileName)
{
try
{
using (Image image = Image.FromFile(fileName))
{
Console.WriteLine($"\nEnhanced metadata for {Path.GetFileName(fileName)}:");
var knownProperties = new Dictionary<int, string>
{
{ 0x010E, "Image Title" },
{ 0x013B, "Artist" },
{ 0x9286, "User Comment" }
};
foreach (PropertyItem prop in image.PropertyItems)
{
if (knownProperties.ContainsKey(prop.Id))
{
string value = System.Text.Encoding.ASCII.GetString(prop.Value).TrimEnd('\0');
Console.WriteLine($" {knownProperties[prop.Id]}: {value}");
}
}
}
}
catch (Exception ex)
{
Console.WriteLine($"Error reading enhanced metadata: {ex.Message}");
}
}
private static void CreateImageWithEXIFData(string fileName)
{
try
{
using (Bitmap bitmap = new Bitmap(400, 300))
using (Graphics graphics = Graphics.FromImage(bitmap))
{
graphics.Clear(Color.White);
graphics.DrawString("EXIF Test Image", new Font("Arial", 20), Brushes.Black, 100, 130);
// Add EXIF data
using (MemoryStream ms = new MemoryStream())
{
bitmap.Save(ms, ImageFormat.Jpeg);
ms.Position = 0;
using (Image image = Image.FromStream(ms))
{
// Add EXIF properties
PropertyItem dateTaken = CreatePropertyItem(0x9003, DateTime.Now.ToString("yyyy:MM:dd HH:mm:ss"));
PropertyItem cameraMake = CreatePropertyItem(0x010F, "C# Camera");
PropertyItem cameraModel = CreatePropertyItem(0x0110, "Image Processor v1.0");
image.SetPropertyItem(dateTaken);
image.SetPropertyItem(cameraMake);
image.SetPropertyItem(cameraModel);
image.Save(fileName, ImageFormat.Jpeg);
}
}
}
Console.WriteLine($"Created image with EXIF data: {fileName}");
}
catch (Exception ex)
{
Console.WriteLine($"Error creating EXIF image: {ex.Message}");
}
}
private static void ReadEXIFData(string fileName)
{
try
{
using (Image image = Image.FromFile(fileName))
{
Console.WriteLine("\nEXIF data:");
var exifProperties = new Dictionary<int, string>
{
{ 0x9003, "Date Taken" },
{ 0x010F, "Camera Make" },
{ 0x0110, "Camera Model" }
};
foreach (PropertyItem prop in image.PropertyItems)
{
if (exifProperties.ContainsKey(prop.Id))
{
string value = System.Text.Encoding.ASCII.GetString(prop.Value).TrimEnd('\0');
Console.WriteLine($" {exifProperties[prop.Id]}: {value}");
}
}
}
}
catch (Exception ex)
{
Console.WriteLine($"Error reading EXIF data: {ex.Message}");
}
}
// Advanced optimization methods
private static void OptimizeForPhotographs(Bitmap image, string baseName)
{
Console.WriteLine($"\nOptimizing {baseName} for photographs...");
// Multiple JPEG quality levels
int[] qualities = { 60, 75, 85, 95 };
foreach (int quality in qualities)
{
string fileName = $"{baseName}_photo_q{quality}.jpg";
SaveJPEGWithQuality(image, fileName, quality);
FileInfo info = new FileInfo(fileName);
Console.WriteLine($" Quality {quality}: {info.Length / 1024.0:F1} KB");
}
}
private static void OptimizeForGraphics(Bitmap image, string baseName)
{
Console.WriteLine($"\nOptimizing {baseName} for graphics...");
// PNG optimization
image.Save($"{baseName}_graphic.png", ImageFormat.Png);
FileInfo pngInfo = new FileInfo($"{baseName}_graphic.png");
Console.WriteLine($" PNG: {pngInfo.Length / 1024.0:F1} KB");
// Reduced color palette
using (Bitmap reducedImage = ReduceColorPalette(image, 256))
{
reducedImage.Save($"{baseName}_graphic_256.png", ImageFormat.Png);
FileInfo reducedInfo = new FileInfo($"{baseName}_graphic_256.png");
Console.WriteLine($" PNG (256 colors): {reducedInfo.Length / 1024.0:F1} KB");
}
}
private static void OptimizeForText(Bitmap image, string baseName)
{
Console.WriteLine($"\nOptimizing {baseName} for text...");
// High-quality PNG for text preservation
image.Save($"{baseName}_text.png", ImageFormat.Png);
FileInfo pngInfo = new FileInfo($"{baseName}_text.png");
Console.WriteLine($" PNG: {pngInfo.Length / 1024.0:F1} KB");
// Try JPEG with high quality (but warn about artifacts)
SaveJPEGWithQuality(image, $"{baseName}_text_q95.jpg", 95);
FileInfo jpgInfo = new FileInfo($"{baseName}_text_q95.jpg");
Console.WriteLine($" JPEG (95%): {jpgInfo.Length / 1024.0:F1} KB (may have artifacts)");
}
private static void OptimizeForMultipleFormats(string baseName, int width, int height)
{
Console.WriteLine("Testing multiple formats for optimal size/quality:");
using (Bitmap image = CreateSampleImage(width, height))
{
var formats = new[]
{
new { Name = "PNG", Action = (Action<string>)(f => image.Save(f, ImageFormat.Png)) },
new { Name = "JPEG 75%", Action = (Action<string>)(f => SaveJPEGWithQuality(image, f, 75)) },
new { Name = "JPEG 90%", Action = (Action<string>)(f => SaveJPEGWithQuality(image, f, 90)) },
new { Name = "GIF", Action = (Action<string>)(f => image.Save(f, ImageFormat.Gif)) },
new { Name = "BMP", Action = (Action<string>)(f => image.Save(f, ImageFormat.Bmp)) }
};
Console.WriteLine("Format\t\tSize (KB)");
foreach (var format in formats)
{
string fileName = $"{baseName}_{format.Name.ToLower().Replace(" ", "_")}.jpg";
if (format.Name != "JPEG 75%" && format.Name != "JPEG 90%")
{
fileName = $"{baseName}_{format.Name.ToLower().Replace(" ", "_")}.{format.Name.ToLower().Split('%')[0]}";
}
format.Action(fileName);
if (File.Exists(fileName))
{
FileInfo info = new FileInfo(fileName);
Console.WriteLine($"{formatName,-15}\t{info.Length / 1024.0:F1}");
}
}
}
}
private static void CompareOptimizationResults(string testName, int width, int height)
{
Console.WriteLine($"\n{testName.ToUpper()} Image Optimization:");
var files = new[]
{
$"optimized_{testName}_photo_q85.jpg",
$"optimized_{testName}_graphic.png",
$"optimized_{testName}_text.png"
};
foreach (string file in files)
{
if (File.Exists(file))
{
FileInfo info = new FileInfo(file);
Console.WriteLine($" {Path.GetFileNameWithoutExtension(file)}: {info.Length / 1024.0:F1} KB");
}
}
}
// Image analysis methods
private class ImageAnalysis
{
public int ColorCount { get; set; }
public int UniqueColors { get; set; }
public bool HasTransparency { get; set; }
public double DetailLevel { get; set; }
public string ImageType { get; set; }
}
private static ImageAnalysis AnalyzeImageCharacteristics(Bitmap image)
{
var analysis = new ImageAnalysis();
var colors = new HashSet<Color>();
Random rand = new Random();
// Sample pixels (not all for performance)
int sampleSize = Math.Min(10000, image.Width * image.Height);
int step = (int)Math.Sqrt((image.Width * image.Height) / sampleSize);
double totalContrast = 0;
int sampleCount = 0;
for (int y = 0; y < image.Height; y += step)
{
for (int x = 0; x < image.Width; x += step)
{
Color pixel = image.GetPixel(x, y);
colors.Add(pixel);
// Check for transparency
if (pixel.A < 255)
analysis.HasTransparency = true;
// Calculate local contrast
if (x > 0 && y > 0)
{
Color leftPixel = image.GetPixel(x - step, y);
Color topPixel = image.GetPixel(x, y - step);
double contrast1 = Math.Abs(pixel.R - leftPixel.R) +
Math.Abs(pixel.G - leftPixel.G) +
Math.Abs(pixel.B - leftPixel.B);
double contrast2 = Math.Abs(pixel.R - topPixel.R) +
Math.Abs(pixel.G - topPixel.G) +
Math.Abs(pixel.B - topPixel.B);
totalContrast += Math.Max(contrast1, contrast2);
sampleCount++;
}
analysis.ColorCount++;
}
}
analysis.UniqueColors = colors.Count;
analysis.DetailLevel = sampleCount > 0 ? totalContrast / sampleCount / 765.0 : 0; // Normalized to 0-1
// Classify image type
if (analysis.UniqueColors < 256)
analysis.ImageType = "Graphic/Logo";
else if (analysis.DetailLevel > 0.3)
analysis.ImageType = "Photograph";
else if (analysis.DetailLevel > 0.1)
analysis.ImageType = "Mixed Content";
else
analysis.ImageType = "Text/Screenshot";
return analysis;
}
private static string RecommendOptimalFormat(ImageAnalysis analysis)
{
if (analysis.HasTransparency)
return "PNG";
if (analysis.UniqueColors < 256 && analysis.ImageType == "Graphic/Logo")
return "PNG";
if (analysis.DetailLevel > 0.3)
return "JPEG";
if (analysis.ImageType == "Text/Screenshot")
return "PNG";
return "JPEG"; // Default for most cases
}
private static void SaveWithRecommendedFormat(Bitmap image, string fileName, string format)
{
switch (format.ToUpper())
{
case "PNG":
image.Save(fileName, ImageFormat.Png);
break;
case "JPEG":
case "JPG":
SaveJPEGWithQuality(image, fileName, 85);
break;
case "GIF":
image.Save(fileName, ImageFormat.Gif);
break;
default:
image.Save(fileName, ImageFormat.Png);
break;
}
}
// Specialized test image creators
private static Bitmap CreatePhotographTestImage(int width, int height)
{
Bitmap bitmap = new Bitmap(width, height);
using (Graphics graphics = Graphics.FromImage(bitmap))
{
// Create realistic photograph-like image with gradients
Random rand = new Random(123);
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
// Create noise and gradients
double noise = rand.NextDouble() * 0.2 - 0.1;
double gradient = (double)x / width;
int r = (int)((100 + gradient * 155) * (1 + noise));
int g = (int)((80 + gradient * 100) * (1 + noise));
int b = (int)((60 + gradient * 80) * (1 + noise));
r = Math.Max(0, Math.Min(255, r));
g = Math.Max(0, Math.Min(255, g));
b = Math.Max(0, Math.Min(255, b));
bitmap.SetPixel(x, y, Color.FromArgb(r, g, b));
}
}
}
return bitmap;
}
private static Bitmap CreateGraphicTestImage(int width, int height)
{
Bitmap bitmap = new Bitmap(width, height);
using (Graphics graphics = Graphics.FromImage(bitmap))
{
graphics.Clear(Color.White);
// Create simple graphics with solid colors
graphics.FillRectangle(Brushes.Red, 50, 50, 100, 100);
graphics.FillEllipse(Brushes.Blue, 200, 100, 120, 120);
graphics.FillPolygon(Brushes.Green, new Point[] {
new Point(350, 200), new Point(400, 300), new Point(300, 300)
});
}
return bitmap;
}
private static Bitmap CreateTextTestImage(int width, int height)
{
Bitmap bitmap = new Bitmap(width, height);
using (Graphics graphics = Graphics.FromImage(bitmap))
{
graphics.Clear(Color.White);
graphics.SmoothingMode = SmoothingMode.AntiAlias;
graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
// Add text
using (Font font = new Font("Arial", 14))
{
graphics.DrawString("This is a sample text image with clear, readable content.",
font, Brushes.Black, 20, 50);
graphics.DrawString("Text images benefit from PNG format to preserve clarity.",
font, Brushes.Black, 20, 80);
graphics.DrawString("JPEG compression can create artifacts around text edges.",
font, Brushes.Black, 20, 110);
}
}
return bitmap;
}
private static Bitmap CreateScreenshotTestImage(int width, int height)
{
Bitmap bitmap = new Bitmap(width, height);
using (Graphics graphics = Graphics.FromImage(bitmap))
{
// Simulate screenshot appearance
graphics.Clear(Color.LightGray);
// Window frame
graphics.FillRectangle(Brushes.White, 10, 30, width - 20, height - 40);
graphics.DrawRectangle(Pens.Black, 10, 30, width - 20, height - 40);
// Title bar
graphics.FillRectangle(Brushes.DarkBlue, 10, 30, width - 20, 30);
graphics.DrawString("Application Window - Screenshot", new Font("Arial", 12, FontStyle.Bold),
Brushes.White, 20, 38);
// Content
graphics.DrawString("Screenshot content with sharp edges and text.",
new Font("Arial", 10), Brushes.Black, 30, 80);
}
return bitmap;
}
private static Bitmap CreateLogoTestImage(int width, int height)
{
Bitmap bitmap = new Bitmap(width, height);
using (Graphics graphics = Graphics.FromImage(bitmap))
{
graphics.Clear(Color.Transparent);
// Simple logo with solid colors
graphics.FillEllipse(Brushes.Red, width/2 - 60, height/2 - 60, 120, 120);
graphics.FillEllipse(Brushes.White, width/2 - 40, height/2 - 40, 80, 80);
graphics.DrawString("LOGO", new Font("Arial", 16, FontStyle.Bold), Brushes.Red,
width/2 - 30, height/2 - 12);
}
return bitmap;
}
private static Bitmap CreateChartTestImage(int width, int height)
{
Bitmap bitmap = new Bitmap(width, height);
using (Graphics graphics = Graphics.FromImage(bitmap))
{
graphics.Clear(Color.White);
// Draw simple bar chart
int[] data = { 60, 120, 90, 150, 80, 110 };
Color[] colors = { Color.Red, Color.Blue, Color.Green, Color.Orange, Color.Purple, Color.Cyan };
int barWidth = width / (data.Length * 2);
for (int i = 0; i < data.Length; i++)
{
int barHeight = (int)(data[i] * height / 200.0);
int x = i * barWidth * 2 + barWidth / 2;
int y = height - barHeight - 50;
graphics.FillRectangle(new SolidBrush(colors[i]), x, y, barWidth, barHeight);
}
// Axes
graphics.DrawLine(Pens.Black, 30, height - 50, width - 30, height - 50);
graphics.DrawLine(Pens.Black, 30, 50, 30, height - 50);
}
return bitmap;
}
private static Bitmap ReduceColorPalette(Bitmap source, int maxColors)
{
// Simple color reduction (for demonstration)
Bitmap result = new Bitmap(source.Width, source.Height);
for (int y = 0; y < source.Height; y++)
{
for (int x = 0; x < source.Width; x++)
{
Color pixel = source.GetPixel(x, y);
// Reduce color depth
int r = (pixel.R / 4) * 4;
int g = (pixel.G / 4) * 4;
int b = (pixel.B / 4) * 4;
result.SetPixel(x, y, Color.FromArgb(pixel.A, r, g, b));
}
}
return result;
}
private static Bitmap CreateSampleImageWithMetadata(int width, int height)
{
Bitmap bitmap = new Bitmap(width, height);
using (Graphics graphics = Graphics.FromImage(bitmap))
{
graphics.Clear(Color.White);
graphics.DrawString("Image with Metadata", new Font("Arial", 16), Brushes.Black,
width/2 - 80, height/2 - 10);
}
return bitmap;
}
public static void RunAllExamples()
{
Console.WriteLine("Image Format Conversion and Optimization Examples");
Console.WriteLine("=================================================");
BasicFormatConversionExample();
JPEGQualityOptimizationExample();
BatchProcessingExample();
MetadataHandlingExample();
AdvancedOptimizationExample();
IntelligentFormatSelectionExample();
Console.WriteLine("\nImage format conversion and optimization examples completed!");
}
}Tools
Tools frequently paired with this sample
Related