Click here to Skip to main content
15,885,278 members
Articles / Web Development / ASP.NET

"Hey! Is That My Car? How to Sharpen a QuickBird Satellite Image Using DotImage"

12 Nov 2007CPOL3 min read 69.4K   31  
Atalasoft leverages their DotImage toolkit to manipulate color channels for the purpose of image enhancement, in this case satellite images. The article is a tutorial on image enhancement and it includes all source code and test images.

This article is in the Product Showcase section for our sponsors at CodeProject. These articles are intended to provide you with information on products and services that we consider useful and of value to developers.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Runtime.Serialization;
using System.Security.Permissions;

using Atalasoft.Imaging;
using Atalasoft.Imaging.Memory;
using Atalasoft.Imaging.ImageProcessing;

namespace ChannelExplorer
{
    class HslConvertCommand : ImageRegionCommand, ISerializable
    {
        private bool _toHsl = true;

        [Browsable(false)]
        public override bool InPlaceProcessing
        {
            get { return true; }
        }		
        
        public HslConvertCommand(bool toHsl)
        {
            _toHsl = toHsl;
        }

        public HslConvertCommand()
		{            
		}

        PixelFormat[] _supportedPixelFormats = 
        {
            PixelFormat.Pixel24bppBgr,
            PixelFormat.Pixel32bppBgr,
        };

        public override PixelFormat[] SupportedPixelFormats
        {
            get { return _supportedPixelFormats; }
        }
        

        protected override void VerifyProperties(AtalaImage image)
        {
        }

        protected override AtalaImage PerformActualCommand(AtalaImage source, AtalaImage dest, Rectangle imageArea, ref ImageResults results)
        {
            PixelMemory.ThrowOnNonContiguous(source.PixelMemory);
            if (dest != null)
            {
                PixelMemory.ThrowOnNonContiguous(dest.PixelMemory);
            }

            //set progress delegate

            byte c1 = 0;
            byte c2 = 0;
            byte c3 = 0;
            byte bpp = (byte)(source.ColorDepth / 8);

            int offset = source.RowStride - imageArea.Width * bpp;
            PixelMemory mem = source.PixelMemory;
            PixelAccessor pixels = mem.AcquirePixelAccessor();

            for (int y = 0; y < imageArea.Height; y++)
            {
                byte[] row = pixels.AcquireScanline(y);
                for (int x = 0; x < imageArea.Width; x++)
                {
                    int i = x * bpp;
                    if (_toHsl)
                    {
                        RgbToHsl(row[i + 2], row[i + 1], row[i + 0], out c1, out c2, out c3);
                        row[i + 0] = c1;
                        row[i + 1] = c2;
                        row[i + 2] = c3;
                    }
                    else
                    {
                        HslToRgb(row[i + 0], row[i + 1], row[i + 2], out c1, out c2, out c3);
                        row[i + 2] = c1;
                        row[i + 1] = c2;
                        row[i + 0] = c3;
                    }                    
                }
                pixels.ReleaseScanline();
            }

            return null;
        }

        /// <summary>
        /// Converts Red, Green and Blue values to hue, Saturation and Luminance.
        /// </summary>
        /// <param name="red">Red</param>
        /// <param name="green">Green</param>
        /// <param name="blue">Blue</param>
        /// <param name="hue">hue</param>
        /// <param name="saturation">Saturation</param>
        /// <param name="luminance">Luminance</param>
        internal static void RgbToHsl(byte red, byte green, byte blue, out byte hue, out byte saturation, out byte luminance)
        {
            double cRed = ((double)red / 255);
            double cGreen = ((double)green / 255);
            double cBlue = ((double)blue / 255);

            double min = (cGreen < cBlue ? cGreen : cBlue);
            min = (cRed < min ? cRed : min);

            double max = (cGreen > cBlue ? cGreen : cBlue);
            max = (cRed > max ? cRed : max);

            // Calculate the Lightness.
            double lum = (max + min) / 2;
            double sat = 0;
            double huet = 0;

            if (max != min)
            {
                // Chromatic
                // Calculate the Saturation
                if (lum > 0.5)
                {
                    sat = (max - min) / (2 - max - min);
                }
                else
                {
                    sat = (max - min) / (max + min);
                }

                // Calculate the hue
                double delta = max - min;

                // A switch wasn't used here because it doesn't like the float.
                if (max == cRed)
                {
                    huet = (cGreen - cBlue) / delta;       // Between Yellow & Magenta
                }
                else if (max == cGreen)
                {
                    huet = (cBlue - cRed) / delta + 2;     // Between Cyan & Yellow
                }
                else
                {
                    huet = (cRed - cGreen) / delta + 4;    // Between Magenta & Cyan
                }

            }

            int lHue = (int)(huet * (240 / 6));
            if (lHue < 0) lHue = lHue + 240;
            hue = (byte)lHue;

            int lSat = (int)(sat * 240);
            saturation = (byte)(lSat > 240 ? 240 : lSat);

            int lLum = (int)(lum * 240);
            luminance = (byte)(lLum > 240 ? 240 : lLum);

        }

        /// <summary>
        /// Converts hue, Saturation and Luminance values to Red, Green and Blue.
        /// </summary>
        /// <param name="hue">hue</param>
        /// <param name="saturation">Saturation</param>
        /// <param name="luminance">Luminance</param>
        /// <param name="red">Red</param>
        /// <param name="green">Green</param>
        /// <param name="blue">Blue</param>
        internal static void HslToRgb(byte hue, byte saturation, byte luminance, out byte red, out byte green, out byte blue)
        {
            double huet = ((double)hue / (240 / 6));
            if (huet >= 5) huet -= 6;
            double sat = ((double)saturation / 240);
            double lum = ((double)luminance / 240);

            double cRed = 0;
            double cGreen = 0;
            double cBlue = 0;

            double min = 0;
            double max = 0;


            if (sat == 0)
            {
                // Achromatic (Grayscale)
                cRed = lum;
                cGreen = lum;
                cBlue = lum;
            }
            else
            {
                // Chromatic case:

                if (lum > 0.5)
                {
                    min = lum - sat * (1 - lum);
                }
                else
                {
                    min = lum * (1 - sat);
                }

                max = 2 * lum - min;

                // TODO: Is there a better way to do this?
                if (huet < 0)
                {
                    cRed = max;
                    cGreen = min;
                    cBlue = cGreen - huet * (max - min);  // Magenta -> cRed
                }
                else if (huet < 1)
                {
                    cRed = max;
                    cBlue = min;
                    cGreen = huet * (max - min) + cBlue;   // cRed -> Yellow
                }
                else if (huet < 2)
                {
                    cGreen = max;
                    cBlue = min;
                    cRed = cBlue - (huet - 2) * (max - min); // Yellow -> cGreen
                }
                else if (huet < 3)
                {
                    cGreen = max;
                    cRed = min;
                    cBlue = (huet - 2) * (max - min) + cRed;  // cGreen -> Cyan
                }
                else if (huet < 4)
                {
                    cBlue = max;
                    cRed = min;
                    cGreen = cRed - (huet - 4) * (max - min); // Cyan -> cBlue
                }
                else
                {
                    cBlue = max;
                    cGreen = min;
                    cRed = (huet - 4) * (max - min) + cGreen; // cBlue -> Magenta
                }

            }
            red = (byte)(cRed * 255);
            green = (byte)(cGreen * 255);
            blue = (byte)(cBlue * 255);

        }



   		#region ISerializable

        protected HslConvertCommand(SerializationInfo info, StreamingContext context)
			: base(info, context)
		{
			if (info == null)
				throw new ArgumentNullException("info", "The parameter 'info' can't be null.");
		}
		
		[SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.SerializationFormatter)]
		public override void GetObjectData(SerializationInfo info, StreamingContext context)
		{
			if (info == null)
				throw new ArgumentNullException("info", "The parameter 'info' can't be null.");
			base.GetObjectData(info, context);
		}
		#endregion


    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Atalasoft, Inc.
United States United States
Lou Franco is the Director of Engineering at Atalasoft, provider of the leading .NET Imaging SDK (DotImage) and the Document Viewer for SharePoint (Vizit).

http://atalasoft.com/products/dotimage
http://vizitsp.com

Comments and Discussions