🎯 Рекомендуемые коллекции
Балансированные коллекции примеров кода из различных категорий, которые вы можете исследовать
Обработка изображений Windows - Примеры C#
Полные примеры обработки изображений C# для платформы Windows, включая манипуляцию изображениями, фильтрацию, преобразование формата и расширенные операции компьютерного зрения
💻 Базовые операции с изображениями csharp
🟢 simple
⭐⭐⭐
Фундаментальные операции с изображениями, включая загрузку, сохранение, изменение размера, обрезку и базовую манипуляцию пикселями с использованием System.Drawing
⏱️ 25 min
🏷️ 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!");
}
}
💻 Продвинутая обработка изображений csharp
🟡 intermediate
⭐⭐⭐⭐
Продвинутые техники обработки изображений, включая свертывающие фильтры, обнаружение краев, морфологические операции и алгоритмы улучшения изображений
⏱️ 35 min
🏷️ 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!");
}
}
💻 Преобразование и оптимизация формата изображений csharp
🟡 intermediate
⭐⭐⭐⭐
Полная система преобразования формата изображений с оптимизацией качества, обработкой метаданных и возможностями пакетной обработки
⏱️ 30 min
🏷️ 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!");
}
}