标准的视觉ECC200二维码解析(值得一看哦,比很多二维码解析都要强力的:-})

//话说手机上也有二维码解析,但是只能说是娱乐用呵呵,我们是工业用 


//运行速度有点慢,可能要500毫秒,以后有空再提速吧.
//上次的解析有些局限,那就是二维码的图像必须是正方形,否则就会出错,这次改过来了,支持各种畸形图像。
 
//先说解析过程吧,
//1.筛选面积较大的区域,找出4个方向的外壳边界,再从这4条线中找出ECC200二维码图的两条主边界
//2.根据两条主边界寻找两条对边
//3.根据4条边的交点创建一个透视变换
//4.根据透视变换计算出旋转角度,把原图校正成标准的ecc200矩阵图
//5.对校正图进行阈值再分配,得出一个效果较好的二值图
//6.分析校正2值图的网格,并进行筛选和平滑化
//7.根据最普遍间距进程错漏网格线的补充
//8.用高斯模糊矩阵计算出网格单元的高斯模糊像素值,如果大于某个阈值说明为0(白色为主的区域),否则为黑色为主的区域1
//9.根据二进制矩阵解码得出解码字符串 ,解码算法是用的一个老外的解码算法,具体细节没去了解,反正把代码抠出来能解析正确就OK

 

 

 

源图

 

解析图,绿色的是主边界,红色的是和主边界形成的平行四边形的两条对边,在两条对边进行精确查找得出两条最终的对边

区域图

 

校正图

二值图

 

网格图

 

 

 

解码图

 

 

 

 

//牵连的代码不下5000行,所以只贴主代码了,有思路就行

 

 

using System;
namespace ImageProcessing.Graph
{

    //表示范围的类
    [Serializable]
    public class Range : ICloneable, IComparable
    {
        public Range() { }
        public Range(double max) { end = max; sort(); }
        public Range(double begin, double end) { this.begin = begin; this.end = end; sort(); }

        double begin = 0, end = 0;

        public double End
        {
            get { return end; }
            set { end = value; sort(); }
        }

        public double Begin
        {
            get { return begin; }
            set { begin = value; sort(); }
        }

        public double Center
        {
            get { return (begin + end) / 2d; }
        }

        public double Lenght
        {
            get { return Math.Abs(end - begin); }
        }

        public Range clone
        {
            get { return new Range(begin, end); }
        }

        void sort()
        {
            if (end < begin)
                GraphHelper.Swap(ref begin, ref end);
        }

        public static Range FromSize(double begine,double length)
        {
            return new Range(begine, begine + length);
        }

        public object Clone() { return clone; }

        public double DistanceTo(Range dest)
        {
            if (IntersectWith(dest)) return 0;
            if (begin > dest.end) return begin - dest.end;
            return dest.begin - end;
        }

        public double CenterDistanctTo(Range dest)
        {
            return Math.Abs(Center - dest.Center);
        }

        public double DistanceTo(double pos)
        {
            if (pos >= begin && pos <= end) return 0;
            else if (pos < begin) return begin - pos;
            else return pos - end;
        }

        public Range Join(Range dest)
        {
            return new Range(Math.Min(begin, dest.begin), Math.Max(end, dest.end));
        }

        public Range Intersect(Range dest)
        {
            if (!IntersectWith(dest)) { return null; }
            else if (Contains(dest)) return clone;
            return new Range(Math.Max(begin, dest.begin), Math.Min(end, dest.end));
        }

        public bool Contains(double d)
        {
            return d >= begin && d <= end;
        }

        public bool Contains(Range dest)
        {
            return dest.begin >= this.begin && dest.end <= end;
        }

        public bool IntersectWith(Range dest)
        {
            return !(dest.begin > end || dest.end < begin);
        }

        public static bool operator ==(Range range1, Range range2)
        {
            if (Equals(range1,null)) return Equals(range2,null);
            else if (Equals(range2, null)) return false;
            return range1.begin == range2.begin && range1.end == range2.end;           
        }

        public static bool operator !=(Range range1, Range range2)
        {
            return !(range1 == range2);
        }

        public override bool Equals(object obj)
        {
            if (Equals(obj, null)) return false;
            if (!(obj is Range)) return false;
            return this == (Range)obj;
        }

        public override int GetHashCode()
        {
            return base.GetHashCode();
        }

        public override string ToString()
        {
            return string.Format("[{0},{1}]", begin, end);
        }

        public int CompareTo(object obj)
        {
            Range dest = (Range)obj;
            if (begin < dest.begin)
                return -1;
            else if (begin == dest.begin)
            {
                if (this.end == dest.end)
                    return 0;
                else if (this.end < dest.end)
                    return -1;
                else
                    return 1;
            }
            else
                return 1;
        }
    }
}

 

 //这3个函数的作用是扫描线段上的指定颜色区域,所属的类为静态类GraphHelper,这个类有3000行,没必要的就不复制了呵呵

class GraphHelper

{

public static List<Line> GetIntersectLines(byte[] threshBuffers, int imgWidth, int imgHeight, bool seachBlackPixel, Line l)
        {
            RectD rd = new RectD(0, 0, imgWidth, imgHeight);

            if (l.StartPos.X >= 0 && l.StartPos.Y >= 0 && l.StartPos.X < imgWidth && l.StartPos.Y < imgHeight)
            {
                return GetIntersectLines(threshBuffers, imgWidth, imgHeight, seachBlackPixel, l.StartPos, l.Direction, l.Length);
            }
            else if (l.EndPos.X >= 0 && l.EndPos.Y >= 0 && l.EndPos.X < imgWidth && l.EndPos.Y < imgHeight)
            {
                return GetIntersectLines(threshBuffers, imgWidth, imgHeight, seachBlackPixel, l.EndPos, l.Direction * -1, l.Length);
            }
            else
            {
                List<PointD> pds = rd.GetIntersect(l);
                if (pds.Count == 2)
                    return GetIntersectLines(threshBuffers, imgWidth, imgHeight, seachBlackPixel, pds[0], pds[1] - pds[0], pds[0].DistanceTo(pds[1]));
            }
            return new List<Line>();
        }

        /// <summary>
        /// 单纯计算起始点沿着dir方向上的与指定颜色区域的的相交线段,如果起始点不在范围内则直接中断
        /// </summary>
        public static List<Line> GetIntersectLines(byte[] threshBuffers, int imgWidth, int imgHeight, bool seachBlackPixel, PointD startPos, PointD direction, double length)
        {
            int px = seachBlackPixel ? 0 : 1;
            List<Line> res = new List<Line>();

            PointD cur = startPos.clone, last = null, prev = null;
            PointD dir = direction.Unit;
            Point pt;

            pt = cur.Point;
            while (InRange(pt, imgWidth, imgHeight))
            {
                if (threshBuffers[pt.X + pt.Y * imgWidth] == px)
                {
                    last = cur.clone;
                    prev = cur.clone;

                    cur += dir;
                    pt = cur.Point;
                    while (InRange(pt, imgWidth, imgHeight) && threshBuffers[pt.X + pt.Y * imgWidth] == px)
                    {
                        prev = cur;
                        cur += dir;
                        pt = cur.Point;
                    }
                    res.Add(new Line(last, prev));
                }
                cur += dir;
                pt = cur.Point;
            }

            return res;
        }

        //查找行或列扫描线上的颜色区域段

        public static List<Range> GetStrideRanges(byte[] threshBuffers, int imgWidth, int imgHeight, bool searchBlackPixel, int position, bool searchRow)
        {
            return GetStrideIntersectLines(threshBuffers, imgWidth, imgHeight, searchBlackPixel, position, searchRow)
                .ConvertAll<Range>(delegate(Line line)
            {
                if (searchRow) return new Range(line.StartPos.X, line.EndPos.X);
                else return new Range(line.StartPos.Y, line.EndPos.Y);
            });
        }

        public static List<Line> GetStrideIntersectLines(byte[] threshBuffers, int imgWidth, int imgHeight, bool seachBlackPixel, int position, bool searchRow)
        {
            PointD start = searchRow ? new PointD(0, position) : new PointD(position, 0);
            PointD dir = searchRow ? new PointD(1, 0) : new PointD(0, 1);
            return GetIntersectLines(threshBuffers, imgWidth, imgHeight, seachBlackPixel, start, dir, searchRow ? imgWidth : imgHeight);
        }

}

 

 //高斯模糊矩阵类

using System;
namespace ImageProcessing.Base.Imaging
{
    public class GaussainMatrix
    {
        public GaussainMatrix(double sigma, int size)
        {
            size |= 1;
            this.size = size;
            this.width = size;
            this.height = size;
            datas = new double[size, size];

            int cx = size / 2, cy = size / 2;
            double dx, dy;
            double sum = 0;
            for (int y = 0; y < size; y++)
            {
                for (int x = 0; x < size; x++)
                {
                    dx = x - cx; dy = y - cy;
                    datas[y, x] = Math.Exp(-1.0 * (dx * dx + dy * dy) / (2.0 * sigma * sigma)) / (Math.Sqrt(2.0 * Math.PI) * sigma);
    

  • 2
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值