Beispiel #1
0
        public unsafe ImageU8 ToImageU8()
        {
            ImageU8 img   = new ImageU8(this.Width, this.Height);
            Grad *  start = this.Start;
            Grad *  end   = start + this.Length;
            float   max   = 0;

            // 找最大值
            Grad *src = start;

            while (src != end)
            {
                max = Math.Max(max, src->Value);
                src++;
            }

            float coeff = max > 255 ? 255f / max : 0;

            src = start;
            Byte *dst = img.Start;

            while (src != end)
            {
                *dst = (Byte)(coeff * src->Value);
                dst++;
                src++;
            }

            return(img);
        }
Beispiel #2
0
        public override IImage Clone()
        {
            ImageU8 img = new ImageU8(this.Width, this.Height);

            img.CloneFrom(this);
            return(img);
        }
Beispiel #3
0
        public unsafe ImageU8 ToGrayscaleImage(double rCoeff, double gCoeff, double bCoeff)
        {
            ImageU8 img = new ImageU8(this.Width, this.Height);
            Argb32 *p   = Start;
            Byte *  to  = img.Start;
            Argb32 *end = p + Length;

            if (Length < 1024)
            {
                while (p != end)
                {
                    *to = (Byte)(p->Red * rCoeff + p->Green * gCoeff + p->Blue * bCoeff);
                    p++;
                    to++;
                }
            }
            else
            {
                int *bCache = stackalloc int[256];
                int *gCache = stackalloc int[256];
                int *rCache = stackalloc int[256];

                const int shift  = 1 << 10;
                int       rShift = (int)(rCoeff * shift);
                int       gShift = (int)(gCoeff * shift);
                int       bShift = shift - rShift - gShift;

                int r = 0, g = 0, b = 0;
                for (int i = 0; i < 256; i++)
                {
                    bCache[i] = b;
                    gCache[i] = g;
                    rCache[i] = r;
                    b        += bShift;
                    g        += gShift;
                    r        += rShift;
                }

                while (p != end)
                {
                    *to = (Byte)((bCache[p->Red] + gCache[p->Green] + rCache[p->Red]) >> 10);
                    p++;
                    to++;
                }
            }
            return(img);
        }
Beispiel #4
0
        public unsafe ImageU8 ToImageU8()
        {
            ImageU8 imgU8  = new ImageU8(this.Width, this.Height);
            int     length = imgU8.Length;
            Int32 * start  = this.Start;
            Byte *  dst    = imgU8.Start;
            Int32 * end    = start + this.Length;

            while (start != end)
            {
                int val = *start;
                *   dst = val < 0 ? (Byte)0 : (val > 255 ? (Byte)255 : (Byte)val);
                start++;
                dst++;
            }
            return(imgU8);
        }
Beispiel #5
0
        public unsafe ImageU8 CopyChannel(int channel)
        {
            if (channel < 0 && channel > 2)
            {
                throw new ArgumentOutOfRangeException("channel");
            }
            int     length = this.Length;
            Byte *  start  = (Byte *)this.StartIntPtr;
            int     size   = sizeof(Rgb24);
            Byte *  end    = start + sizeof(Rgb24) * length;
            ImageU8 imgU8  = new ImageU8(this.Width, this.Height);
            Byte *  dst    = imgU8.Start;

            while (start != end)
            {
                *dst = start[channel];
                start += size;
                dst++;
            }
            return(imgU8);
        }
Beispiel #6
0
        /// <summary>
        /// 进行中值滤波。
        /// </summary>
        /// <param name="medianRadius">
        /// 中值滤波的核半径,不得小于1.
        /// </param>
        public unsafe void ApplyMedianFilter(int medianRadius)
        {
            if (medianRadius > 0)
            {
                // 进行中值滤波
                using (ImageU8 copy = this.Clone() as ImageU8)
                {
                    int    size   = medianRadius * 2 + 1;
                    int    count  = 0;
                    byte[] data   = new byte[size * size];
                    int    height = this.Height;
                    int    width  = this.Width;
                    for (int y = 0; y < height; y++)
                    {
                        for (int x = 0; x < width; x++)
                        {
                            count = 0;
                            for (int h = -medianRadius; h <= medianRadius; h++)
                            {
                                for (int w = -medianRadius; w <= medianRadius; w++)
                                {
                                    int hh = y + h;
                                    int ww = x + w;
                                    if (hh >= 0 && hh < height && ww >= 0 && ww < width)
                                    {
                                        data[count] = copy[hh, ww];
                                        count++;
                                    }
                                }
                            }

                            Array.Sort(data, 0, count);
                            int  m      = count >> 1;
                            byte median = data[m];
                            this[y, x] = median;
                        }
                    }
                }
            }
        }
Beispiel #7
0
        /// <summary>
        /// 使用 hilditch 算法进行细化
        /// </summary>
        public unsafe void Thinning(Byte foreground = 255)
        {
            Byte * start      = this.Start;
            Int32  width      = this.Width;
            Int32  height     = this.Height;
            Int32 *list       = stackalloc Int32[8];
            Byte   background = (Byte)(255 - foreground);
            Int32  length     = this.Length;

            using (ImageU8 mask = new ImageU8(this.Width, this.Height))
            {
                mask.Fill(0);

                Boolean loop = true;
                while (loop == true)
                {
                    loop = false;
                    for (Int32 r = 1; r < height - 1; r++)
                    {
                        for (Int32 c = 1; c < width - 1; c++)
                        {
                            Byte *p = start + r * width + c;

                            // 条件1:p 必须是前景点
                            if (*p != foreground)
                            {
                                continue;
                            }

                            //  p3  p2  p1
                            //  p4  p   p0
                            //  p5  p6  p7
                            // list 存储的是补集,即前景点为0,背景点为1,以方便联结数的计算
                            FillNeighbors(p, list, width, foreground);

                            // 条件2:p0,p2,p4,p6 不皆为前景点
                            if (list[0] == 0 && list[2] == 0 && list[4] == 0 && list[6] == 0)
                            {
                                continue;
                            }

                            // 条件3: p0~p7至少两个是前景点
                            Int32 count = 0;
                            for (int i = 0; i < 8; i++)
                            {
                                count += list[i];
                            }

                            if (count > 6)
                            {
                                continue;
                            }

                            // 条件4:联结数等于1
                            if (DetectConnectivity(list) != 1)
                            {
                                continue;
                            }

                            // 条件5: 假设p2已标记删除,则令p2为背景,不改变p的联结数
                            if (mask[r - 1, c] == 1)
                            {
                                list[2] = 1;
                                if (DetectConnectivity(list) != 1)
                                {
                                    continue;
                                }
                                list[2] = 0;
                            }

                            // 条件6: 假设p4已标记删除,则令p4为背景,不改变p的联结数
                            if (mask[r, c - 1] == 1)
                            {
                                list[4] = 1;
                                if (DetectConnectivity(list) != 1)
                                {
                                    continue;
                                }
                            }
                            mask[r, c] = 1; // 标记删除
                            loop       = true;
                        }
                    }

                    for (int i = 0; i < length; i++)
                    {
                        if (mask[i] == 1)
                        {
                            this[i] = background;
                        }
                    }
                }
            }
        }
Beispiel #8
0
        public unsafe void ApplyCannyEdgeDetector(double gaussianSiama = 1.4, int gaussianSize = 5, byte lowThreshold = 20, byte highThreshold = 100)
        {
            ImageU8 copy   = this.Clone() as ImageU8;
            int     startX = 1;
            int     startY = 1;
            int     width  = this.Width;
            int     height = this.Height;

            int stopX = width - 1;
            int stopY = height - 1;
            int ww    = width - 2;
            int hh    = height - 2;

            // orientation array
            byte[] orients = new byte[ww * hh];
            // gradients array
            float[,] gradients = new float[this.Width, this.Height];
            float  maxGradient = float.NegativeInfinity;
            double gx, gy;
            double orientation, toAngle = 180.0 / System.Math.PI;
            float  leftPixel = 0, rightPixel = 0;

            // 第一步,Gauss 平滑
            copy.ApplyGaussianBlur(gaussianSiama, gaussianSize);
            byte *start = copy.Start + startX;
            int   o     = 0;

            for (int y = startY; y < stopY; y++)
            {
                byte *line = start + y * width;
                byte *p    = line;
                for (int x = startX; x < stopX; x++, p++, o++)
                {
                    gx = p[-width + 1] + p[width + 1]
                         - p[-width - 1] - p[width - 1]
                         + 2 * (p[1] - p[-1]);
                    gy = p[-width - 1] + p[-width + 1]
                         - p[width - 1] - p[width + 1]
                         + 2 * (p[-width] - p[width]);
                    gradients[x, y] = (float)Math.Sqrt(gx * gx + gy * gy);
                    if (gradients[x, y] > maxGradient)
                    {
                        maxGradient = gradients[x, y];
                    }

                    // get orientation
                    if (gx == 0)
                    {
                        orientation = (gy == 0) ? 0 : 90;
                    }
                    else
                    {
                        double div = gy / gx;
                        // handle angles of the 2nd and 4th quads
                        if (div < 0)
                        {
                            orientation = 180 - System.Math.Atan(-div) * toAngle;
                        }
                        // handle angles of the 1st and 3rd quads
                        else
                        {
                            orientation = System.Math.Atan(div) * toAngle;
                        }

                        // get closest angle from 0, 45, 90, 135 set
                        if (orientation < 22.5)
                        {
                            orientation = 0;
                        }
                        else if (orientation < 67.5)
                        {
                            orientation = 45;
                        }
                        else if (orientation < 112.5)
                        {
                            orientation = 90;
                        }
                        else if (orientation < 157.5)
                        {
                            orientation = 135;
                        }
                        else
                        {
                            orientation = 0;
                        }
                    }

                    // save orientation
                    orients[o] = (byte)orientation;
                }
            }

            // STEP 3 - suppres non maximums
            o     = 0;
            start = this.Start + startX;
            for (int y = startY; y < stopY; y++)
            {
                byte *line = start + y * width;
                byte *p    = line;
                // for each pixel
                for (int x = startX; x < stopX; x++, p++, o++)
                {
                    // get two adjacent pixels
                    switch (orients[o])
                    {
                    case 0:
                        leftPixel  = gradients[x - 1, y];
                        rightPixel = gradients[x + 1, y];
                        break;

                    case 45:
                        leftPixel  = gradients[x - 1, y + 1];
                        rightPixel = gradients[x + 1, y - 1];
                        break;

                    case 90:
                        leftPixel  = gradients[x, y + 1];
                        rightPixel = gradients[x, y - 1];
                        break;

                    case 135:
                        leftPixel  = gradients[x + 1, y + 1];
                        rightPixel = gradients[x - 1, y - 1];
                        break;
                    }
                    // compare current pixels value with adjacent pixels
                    if ((gradients[x, y] < leftPixel) || (gradients[x, y] < rightPixel))
                    {
                        *p = 0;
                    }
                    else
                    {
                        *p = (byte)(gradients[x, y] / maxGradient * 255);
                    }
                }
            }

            // STEP 4 - hysteresis
            start = this.Start + startX;
            for (int y = startY; y < stopY; y++)
            {
                byte *line = start + y * width;
                byte *p    = line;
                for (int x = startX; x < stopX; x++, p++)
                {
                    if (*p < highThreshold)
                    {
                        if (*p < lowThreshold)
                        {
                            // non edge
                            *p = 0;
                        }
                        else
                        {
                            // check 8 neighboring pixels
                            if ((p[-1] < highThreshold) &&
                                (p[1] < highThreshold) &&
                                (p[-width - 1] < highThreshold) &&
                                (p[-width] < highThreshold) &&
                                (p[-width + 1] < highThreshold) &&
                                (p[width - 1] < highThreshold) &&
                                (p[width] < highThreshold) &&
                                (p[width + 1] < highThreshold))
                            {
                                *p = 0;
                            }
                        }
                    }
                }
            }

            // STEP 4 将第1行,最后一行,第0列,最后1列

            // 第1行
            start = this.Start;
            byte *end = start + width;

            while (start != end)
            {
                *start = 0;
                start++;
            }

            // 最后一行
            start = this.Start + width * height - width;
            end   = start + width;
            while (start != end)
            {
                *start = 0;
                start++;
            }

            // 第一列和最后一列
            start = this.Start;
            for (int y = 0; y < height; y++, start += width)
            {
                start[0]         = 0;
                start[width - 1] = 0;
            }
        }
Beispiel #9
0
        public unsafe void SkeletonizeByMidPoint(Byte foreground = 255)
        {
            using (ImageU8 mask = new ImageU8(this.Width, this.Height))
            {
                mask.Fill(0);
                Int32 width  = this.Width;
                Int32 height = this.Height;
                for (Int32 r = 0; r < height; r++)
                {
                    Int32 lineStart = -1;
                    for (Int32 c = 0; c < width; c++)
                    {
                        if (this[r, c] == foreground)
                        {
                            if (lineStart == -1)
                            {
                                lineStart = c;
                            }
                        }
                        else
                        {
                            if (lineStart != -1)
                            {
                                mask[r, (lineStart + c) / 2] = 1;
                                lineStart = -1;
                            }
                        }
                    }
                }

                for (Int32 c = 0; c < width; c++)
                {
                    Int32 lineStart = -1;
                    for (Int32 r = 0; r < height; r++)
                    {
                        if (this[r, c] == foreground)
                        {
                            if (lineStart == -1)
                            {
                                lineStart = r;
                            }
                        }
                        else
                        {
                            if (lineStart != -1)
                            {
                                mask[(lineStart + r) / 2, c] = 1;
                                lineStart = -1;
                            }
                        }
                    }
                }

                Byte  bg     = (Byte)(255 - foreground);
                Int32 length = this.Length;
                for (int i = 0; i < length; i++)
                {
                    if (mask[i] == 1)
                    {
                        this[i] = foreground;
                    }
                    else
                    {
                        this[i] = bg;
                    }
                }
            }
        }