大赵传奇

GIS解决方案,webgis , 桌面、数据、服务--QQ276605216

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

先来c#的,

        private void button1_Click(object sender, EventArgs e)
        {
            var fileName = @"d:\Screenshot4.jpg";
            fileName = @"d:\Screenshot6.png";
            //mat = new Mat(fileName);
            //pictureBox1.SizeMode = PictureBoxSizeMode.Zoom;
            //pictureBox1.Image = mat.ToBitmap();


            var img = Cv2.ImRead(fileName);
            var pos = detect(img);
            foreach (var p in pos)
            {
                Debug.WriteLine(p);
            }

        }


        private List<OpenCvSharp.Point> detect(Mat img)
        {
            var pos = new List<OpenCvSharp.Point>();
            //1.转化成灰度图
            Mat gray = img.CvtColor(ColorConversionCodes.BGR2GRAY);
            //Cv2.CvtColor(img, gray, ColorConversionCodes.BGR2GRAY);
            //2. 形态学变换的预处理,得到可以查找矩形的图片
            Mat dilation = preprocess(gray);
            //3. 查找和筛选文字区域
            var region = findTextRegion(dilation);
            //4. 用绿线画出这些找到的轮廓
            var nrootdir = @"d:/cut_image/";
            var nrootdir2 = @"d:/cut_image2/";
            int i = 0;
            int j = 1;
            foreach (var item in region)
            {
                var newimage=img[item.Y>0?item.Y:0,  item.Y+item.Height,    item.X>0?item.X:0, item.X+item.Width];
                //放大4倍
                Mat img_gray = new Mat();
                //var img_gray = img.Resize(newimage.Size(), 4, 4, InterpolationFlags.Nearest);
                OpenCvSharp.Size size = new OpenCvSharp.Size();
                Cv2.Resize(newimage, img_gray, size, 4, 4, InterpolationFlags.Nearest);

                var file_name = nrootdir + i.ToString() + ".jpg";                
                Cv2.ImWrite(file_name, newimage);

                var file_sub = "";
                var gray2 = img_gray.CvtColor(ColorConversionCodes.BGR2GRAY);
                var dilation2 = preprocess(gray2);
                var region2 = findTextRegion(dilation2);
                foreach (var item2 in region2)
                {
                    var newimage2 = img_gray[item2.Y>0?item2.Y:0,item2.Y+item2.Height,   item2.X>0?item2.X:0, item2.X+item2.Width];
                    if (newimage2.Size().Width > 0)
                    {
                        file_sub = nrootdir2 + i.ToString() + "-" + j.ToString() + ".jpg";
                        Cv2.ImWrite(file_sub, newimage2);
                        j++;
                        pos.Add(new OpenCvSharp.Point(item.X+item2.X/4+item2.Width/8, item.Y+item2.Y/4+item2.Height/8));
                    }
                }
                //如果第一次检测只有一个文字区域,第二次放大再检测则没有。这样直接复制过去
                if (region2 == null || region2.Count == 0)
                {
                    file_sub = nrootdir2 + i.ToString() + "-0" + ".jpg";
                    Cv2.ImWrite(file_sub, newimage);
                    pos.Add(new OpenCvSharp.Point(item.X+item.Width/2, item.Y+item.Height/2));
                }
                i++;

                //画线
                //img.Rectangle(item, new Scalar(0, 255, 0), 2);
            }

            //Cv2.ImShow("img", img);

            return pos;
        }


        public List<Rect> findTextRegion(Mat dilation)
        {
            List<Rect> region = new List<Rect>();
            // 1. 查找轮廓
            OpenCvSharp.Point[][] contours;
            HierarchyIndex[] hierarchly;
            Rect biggestContourRect = new Rect();

            Cv2.FindContours(dilation, out contours, out hierarchly, RetrievalModes.CComp, ContourApproximationModes.ApproxSimple);

            // 2. 筛选那些面积小的
            int i = 0;
            foreach (OpenCvSharp.Point[] contour in contours)
            {
                double area = Cv2.ContourArea(contour);
                //面积小的都筛选掉
                if (area < 1000 || area> 10000)
                {
                    continue;
                }
                //轮廓近似,作用很小
                double epsilon = 0.001 * Cv2.ArcLength(contour, true);
                RotatedRect rect = Cv2.MinAreaRect(contour);

                //找到最小的矩形
                biggestContourRect = Cv2.BoundingRect(contour);

                if (biggestContourRect.Height > (biggestContourRect.Width * 1.2))
                {
                    continue;
                }
                region.Add(biggestContourRect);                
            }
            return region;
            //pictureBox1.Image = mat.ToBitmap();
            
        }

        private Mat preprocess(Mat gray)
        {
            //1.Sobel算子,x方向求梯度
            Mat sobel = new Mat();
            Cv2.Sobel(gray, sobel, MatType.CV_8U, 1, 0, 3);

            //2.二值化
            Mat binary = new Mat();
            Cv2.Threshold(sobel, binary, 0, 255, ThresholdTypes.Otsu | ThresholdTypes.Binary);

            //3. 膨胀和腐蚀操作的核函数
            Mat element1 = new Mat();
            Mat element2 = new Mat();
            OpenCvSharp.Size size1 = new OpenCvSharp.Size(36, 9);
            OpenCvSharp.Size size2 = new OpenCvSharp.Size(24, 6);

            element1 = Cv2.GetStructuringElement(MorphShapes.Rect, size1);
            element2 = Cv2.GetStructuringElement(MorphShapes.Rect, size2);

            //4. 膨胀一次,让轮廓突出
            Mat dilation = new Mat();
            Cv2.Dilate(binary, dilation, element2);

            //5. 腐蚀一次,去掉细节,如表格线等。注意这里去掉的是竖直的线
            Mat erosion = new Mat();
            Cv2.Erode(dilation, erosion, element1);

            //6. 再次膨胀,让轮廓明显一些
            Mat dilation2 = new Mat();
            Cv2.Dilate(erosion, dilation2, element2, null, 2);
            return dilation2;
        }
View Code

python3的,

# coding=utf-8
import cv2
import numpy as np
import os

def preprocess(gray):
    # 1. Sobel算子,x方向求梯度
    sobel = cv2.Sobel(gray, cv2.CV_8U, 1, 0, ksize = 3)
    # 2. 二值化
    ret, binary = cv2.threshold(sobel, 0, 255, cv2.THRESH_OTSU+cv2.THRESH_BINARY)
    # 3. 膨胀和腐蚀操作的核函数
    element1 = cv2.getStructuringElement(cv2.MORPH_RECT, (36, 9))
    element2 = cv2.getStructuringElement(cv2.MORPH_RECT, (24, 6))
    # 4. 膨胀一次,让轮廓突出
    dilation = cv2.dilate(binary, element2, iterations = 1)
    # 5. 腐蚀一次,去掉细节,如表格线等。注意这里去掉的是竖直的线
    erosion = cv2.erode(dilation, element1, iterations = 1)
    # 6. 再次膨胀,让轮廓明显一些
    dilation2 = cv2.dilate(erosion, element2, iterations = 2)
    # # 7. 存储中间图片 
    # cv2.imwrite("binary.png", binary)
    # cv2.imwrite("dilation.png", dilation)
    # cv2.imwrite("erosion.png", erosion)
    # cv2.imwrite("dilation2.png", dilation2)
    return dilation2
def findTextRegion(img):
    region = []
    # 1. 查找轮廓
    contours, hierarchy = cv2.findContours(img, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_SIMPLE)
    # 2. 筛选那些面积小的
    for i in range(len(contours)):
        cnt = contours[i]
        # 计算该轮廓的面积
        area = cv2.contourArea(cnt) 
        # 面积小的都筛选掉
        if(area < 1000 or area> 10000):  #也过滤太的外框
            continue
        # 轮廓近似,作用很小
        epsilon = 0.001 * cv2.arcLength(cnt, True)
        approx = cv2.approxPolyDP(cnt, epsilon, True)
        # 找到最小的矩形,该矩形可能有方向
        rect = cv2.minAreaRect(cnt)
        # print ("rect is: ",rect)
        # box是四个点的坐标
        box = cv2.boxPoints(rect)
        box = np.int0(box)
        # 计算高和宽
        height = abs(box[0][1] - box[2][1])
        width = abs(box[0][0] - box[2][0])
        # 筛选那些太细的矩形,留下扁的
        if(height > width * 1.2):
            continue
        region.append(box)
    return region

def detect(img):
    # 1.  转化成灰度图
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    # 2. 形态学变换的预处理,得到可以查找矩形的图片
    dilation = preprocess(gray)
    # 3. 查找和筛选文字区域
    region = findTextRegion(dilation)
    # 4. 用绿线画出这些找到的轮廓
    for box in region:
        cv2.drawContours(img, [box], 0, (0, 0, 0), 2)
    cv2.namedWindow("img", cv2.WINDOW_NORMAL)
    cv2.imshow("img", img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()




    nrootdir=("d:/cut_image/")
    if not os.path.isdir(nrootdir):
        os.makedirs(nrootdir)
    nrootdir2=("d:/cut_image2/")
    if not os.path.isdir(nrootdir2):
        os.makedirs(nrootdir2)

    pos=[]
    idx=1
    for i in range(0,len(region)): 
        px, py, w, h = cv2.boundingRect(region[i])  
        #print(i,px,py,w,h)
        
        #cv2.rectangle(img, (x,y), (x+w,y+h), (153,153,0), 5)
        # newimage=img[y+2:y+h-2,x+2:x+w-2] # 先用y确定高,再用x确定宽
        newimage=img[py if py>0 else 0:py+h,px if px>0 else 0:px+w]
        # 放大4倍
        img_gray=cv2.resize(newimage,(0,0),fx=4,fy=4,interpolation=cv2.INTER_NEAREST)
        file_name=nrootdir+str(i)+".jpg"
        cv2.imwrite(file_name, newimage)

        gray2 = cv2.cvtColor(img_gray, cv2.COLOR_BGR2GRAY)
        dilation2 = preprocess(gray2)
        region2 = findTextRegion(dilation2)
        for j in range(0,len(region2)): 
            x2, y2, w2, h2 = cv2.boundingRect(region2[j])  
            cx = x2+w2/2
            cy = y2+h2/2 
            #print(j,x2,y2,w2,h2, (cx, cy))
            newimage2=img_gray[y2 if y2>0 else 0:y2+h2,x2 if x2>0 else 0:x2+w2]
            if newimage2.size>0:
                file_name=nrootdir2+str(idx)+".jpg"
                cv2.imwrite(file_name, newimage2)
                idx+=1
                pos.append((px+cx/4,py+cy/4))
    return pos

    # cv2.imwrite("contours.png", img)
    # cv2.waitKey(0)
    # cv2.destroyAllWindows()


# img = cv2.imread("d:\Screenshot1.png")
img = cv2.imread("d:\Screenshot4.jpg")
pos=detect(img)
for p in pos:
    print(p)
View Code

 

 

 

 然后坐标就得到了

(x:1513 y:955)
(x:1036 y:949)
(x:993 y:944)
(x:811 y:947)
(x:751 y:939)
(x:871 y:934)
(x:815 y:920)
(x:754 y:912)
。。。

还有然后。

posted on 2021-07-21 16:14  赵长青  阅读(284)  评论(0)    收藏  举报