Windows 图像处理 - C# 示例

Windows平台C#图像处理示例,包括图像操作、过滤、格式转换和高级计算机视觉操作

💻 基本图像操作 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!");
    }
}