美文网首页
图片处理

图片处理

作者: Canon_2020 | 来源:发表于2020-04-20 09:08 被阅读0次
    import cv2
    import os
    from math import *
    import numpy as np
    from PIL import Image
    import matplotlib.pyplot as plt
    
    
    # 当前所在的目录
    dir_path = os.path.dirname(os.path.realpath(__file__))
    
    img = cv2.imread(dir_path + "/code_img/randomCode1.jpeg")
    
    height, width = img.shape[:2]
    degree = 15
    # 旋转后的尺寸
    heightNew = int(width*fabs(sin(radians(degree)))+height*fabs(cos(radians(degree))))
    widthNew = int(height*fabs(sin(radians(degree)))+width*fabs(cos(radians(degree))))
    
    matRotation = cv2.getRotationMatrix2D((width/2, height/2), degree, 1)
    
    matRotation[0, 2] += (widthNew-width)/2  # 重点在这步,目前不懂为什么加这步
    matRotation[1, 2] += (heightNew-height)/2  # 重点在这步
    
    imgRotation = cv2.warpAffine(img, matRotation, (widthNew, heightNew), borderValue=(255, 255, 255))
    
    cv2.imshow("img", img)
    cv2.imshow("imgRotation", imgRotation)
    cv2.waitKey(0)
    
    
    #!/usr/local/python3
    # -*- coding: utf-8 -*-
    # @Date        : 2018-04-15 09:00:00
    # @Author    : Canon
    # @Link        : https://www.python.org
    # @Version : 3.6.1
    
    """
    pip install Pillow
    pip install pytesseract
    pip install numpy
    pip install matplotlib
    pip install opencv-contrib-python / pip install opencv-python
    
    将 cv2.cp36-win_amd64.pyd, cv.py 文件移入python包所在的文件夹 (python安装位置/lib/site-packages)
    
    https://www.cnblogs.com/qqandfqr/p/7866650.html
    http://www.360doc.com/content/17/0225/20/28294195_631980376.shtml
    
    参考链接:
    tesserocr GitHub:https://github.com/sirfz/tesserocr
    tesserocr PyPI:https://pypi.python.org/pypi/tesserocr
    pytesserocr GitHub:https://github.com/madmaze/pytesseract
    pytesserocr PyPI:https://pypi.org/project/pytesseract/
    tesseract下载地址:http://digi.bib.uni-mannheim.de/tesseract
    tesseract GitHub:https://github.com/tesseract-ocr/tesseract
    tesseract 语言包:https://github.com/tesseract-ocr/tessdata
    tesseract文档:https://github.com/tesseract-ocr/tesseract/wiki/Documentation
    
    """
    
    from PIL import Image
    import pytesseract
    from pytesseract import image_to_string
    from fnmatch import fnmatch
    from queue import Queue
    import matplotlib.pyplot as plt
    import cv2
    import time
    import os
    
    # 当前所在的目录
    dir_path = os.path.dirname(os.path.realpath(__file__))
    
    
    def clear_border(img, img_name):
        '''
        去除边框
        '''
        filename = dir_path + '/out_img/' + img_name.split('.')[0] + '-clearBorder.jpg'
        # 显示图像尺寸, 0: 图片宽度, 1: 图片高度, 2: 图片通道数
        h, w = img.shape[:2]
        # !!!opencv矩阵点是反的
        # 遍历像素点, 找到四个边框上的所有点, 把他们都改为白色
        for y in range(0, w):
            for x in range(0, h):
                if y == 0 or y == w-1:
                    img[x, y] = 255
                if x == 0 or x == h-1:
                    # 白色
                    img[x, y] = 255
        cv2.imwrite(filename, img)
        return img
    
    
    def interference_line(img, img_name):
        '''
        干扰线降噪
        '''
        filename = dir_path + '/out_img/' + img_name.split('.')[0] + '-interferenceline.jpg'
        h, w = img.shape[:2]
        # !!!opencv矩阵点是反的
        # img[1, 2] 1:图片的高度,2:图片的宽度
        for y in range(1, w - 1):
            for x in range(1, h - 1):
                count = 0
                if img[x, y - 1] > 245:
                    count = count + 1
                if img[x, y + 1] > 245:
                    count = count + 1
                if img[x - 1, y] > 245:
                    count = count + 1
                if img[x + 1, y] > 245:
                    count = count + 1
                if count > 2:
                    img[x, y] = 255
        cv2.imwrite(filename, img)
        return img
    
    
    def interference_point(img, img_name, x=0, y=0):
        """
        点降噪
        9邻域框,以当前点为中心的田字框,黑点个数
        :param x:
        :param y:
        :return:
        """
        filename = dir_path + '/out_img/' + img_name.split('.')[0] + '-interferencePoint.jpg'
        # todo 判断图片的长宽度下限
        # 当前像素点的值
        cur_pixel = img[x, y]
        height, width = img.shape[:2]
        for y in range(0, width - 1):
            for x in range(0, height - 1):
                # 第一行
                if y == 0:
                    # 左上顶点, 4邻域
                    if x == 0:
                        # 中心点旁边3个点
                        sum = int(cur_pixel) \
                                  + int(img[x, y + 1]) \
                                  + int(img[x + 1, y]) \
                                  + int(img[x + 1, y + 1])
                        if sum <= 2 * 245:
                            img[x, y] = 0
                    # 右上顶点
                    elif x == height - 1:
                        sum = int(cur_pixel) \
                                  + int(img[x, y + 1]) \
                                  + int(img[x - 1, y]) \
                                  + int(img[x - 1, y + 1])
                        if sum <= 2 * 245:
                            img[x, y] = 0
                    else:
                        # 最上非顶点, 6邻域
                        sum = int(img[x - 1, y]) \
                                  + int(img[x - 1, y + 1]) \
                                  + int(cur_pixel) \
                                  + int(img[x, y + 1]) \
                                  + int(img[x + 1, y]) \
                                  + int(img[x + 1, y + 1])
                        if sum <= 3 * 245:
                            img[x, y] = 0
                # 最下面一行
                elif y == width - 1:
                    # 左下顶点
                    if x == 0:
                        # 中心点旁边3个点
                        sum = int(cur_pixel) \
                                  + int(img[x + 1, y]) \
                                  + int(img[x + 1, y - 1]) \
                                  + int(img[x, y - 1])
                        if sum <= 2 * 245:
                            img[x, y] = 0
                    # 右下顶点
                    elif x == height - 1:
                        sum = int(cur_pixel) \
                                  + int(img[x, y - 1]) \
                                  + int(img[x - 1, y]) \
                                  + int(img[x - 1, y - 1])
                        if sum <= 2 * 245:
                            img[x, y] = 0
                    # 最下非顶点,6邻域
                    else:
                        sum = int(cur_pixel) \
                                  + int(img[x - 1, y]) \
                                  + int(img[x + 1, y]) \
                                  + int(img[x, y - 1]) \
                                  + int(img[x - 1, y - 1]) \
                                  + int(img[x + 1, y - 1])
                        if sum <= 3 * 245:
                            img[x, y] = 0
                # y不在边界
                else:
                    # 左边非顶点
                    if x == 0:
                        sum = int(img[x, y - 1]) \
                                  + int(cur_pixel) \
                                  + int(img[x, y + 1]) \
                                  + int(img[x + 1, y - 1]) \
                                  + int(img[x + 1, y]) \
                                  + int(img[x + 1, y + 1])
                        if sum <= 3 * 245:
                            img[x, y] = 0
                    # 右边非顶点
                    elif x == height - 1:
                        sum = int(img[x, y - 1]) \
                                  + int(cur_pixel) \
                                  + int(img[x, y + 1]) \
                                  + int(img[x - 1, y - 1]) \
                                  + int(img[x - 1, y]) \
                                  + int(img[x - 1, y + 1])
                        if sum <= 3 * 245:
                            img[x, y] = 0
                    # 具备9领域条件的
                    else:
                        sum = int(img[x - 1, y - 1]) \
                                  + int(img[x - 1, y]) \
                                  + int(img[x - 1, y + 1]) \
                                  + int(img[x, y - 1]) \
                                  + int(cur_pixel) \
                                  + int(img[x, y + 1]) \
                                  + int(img[x + 1, y - 1]) \
                                  + int(img[x + 1, y]) \
                                  + int(img[x + 1, y + 1])
                        if sum <= 4 * 245:
                            img[x, y] = 0
        cv2.imwrite(filename, img)
        return img
    
    
    def _get_dynamic_binary_image(filedir, img_name):
        '''
        自适应阀值二值化
        '''
        filename = dir_path + '/out_img/' + img_name.split('.')[0] + '-binary.jpg'
        filename1 = dir_path + '/out_img/' + img_name.split('.')[0] + '-rotate.jpg'
        img_name = filedir + '/' + img_name
        # 图片旋转10°
        image = Image.open(img_name)
        im2 = image.rotate(10)
        # 将旋转后的黑色区域改为白色
        img_array = im2.load()
        w, h = im2.size
        for y in range(0, h):
            for x in range(0, w):
                if img_array[x, y] == (0, 0, 0):
                    img_array[x, y] = (255, 255, 255)
        im2.save(filename)
        im2.save(filename1)
        # 读取图片
        im = cv2.imread(filename)
        # 图片灰值化
        im = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
        # 图片二值化
        th1 = cv2.adaptiveThreshold(im, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 21, 1)
        cv2.imwrite(filename, th1)
        return th1
    
    
    def _get_static_binary_image(img, threshold=140):
        '''
        手动二值化
        '''
        img = Image.open(img)
        img = img.convert('L')
        pixdata = img.load()
        w, h = img.size
        for y in range(h):
            for x in range(w):
                if pixdata[x, y] < threshold:
                    pixdata[x, y] = 0
                else:
                    pixdata[x, y] = 255
        return img
    
    
    def cfs(im, x_fd, y_fd):
        '''
        用队列和集合记录遍历过的像素坐标代替单纯递归以解决cfs访问过深问题
        '''
        xaxis = []
        yaxis = []
        visited = set()
        q = Queue()
        q.put((x_fd, y_fd))
        visited.add((x_fd, y_fd))
        # 四邻域
        offsets = [(1, 0), (0, 1), (-1, 0), (0, -1)]
    
        while not q.empty():
            x, y = q.get()
            for xoffset, yoffset in offsets:
                x_neighbor, y_neighbor = x + xoffset, y + yoffset
                if (x_neighbor,y_neighbor) in (visited):
                    # 已经访问过了
                    continue
                visited.add((x_neighbor, y_neighbor))
                try:
                    if im[x_neighbor, y_neighbor] == 0:
                        xaxis.append(x_neighbor)
                        yaxis.append(y_neighbor)
                        q.put((x_neighbor,y_neighbor))
                except IndexError:
                    pass
        # print(xaxis)
        if (len(xaxis) == 0 | len(yaxis) == 0):
            xmax = x_fd + 1
            xmin = x_fd
            ymax = y_fd + 1
            ymin = y_fd
        else:
            xmax = max(xaxis)
            xmin = min(xaxis)
            ymax = max(yaxis)
            ymin = min(yaxis)
            # ymin, ymax = sort(yaxis)
        return ymax,ymin,xmax,xmin
    
    
    def detectFgPix(im, xmax):
        '''
        搜索区块起点
        '''
        h, w = im.shape[:2]
        for y_fd in range(xmax+1, w):
            for x_fd in range(h):
                if im[x_fd, y_fd] == 0:
                    return x_fd, y_fd
    
    
    def CFS(im):
        '''
        切割字符位置
        思路:
        字符切割的思路就是找到一个黑色的点,然后在遍历与他相邻的黑色的点,
        直到遍历完所有的连接起来的黑色的点,找出这些点中的最高的点、最低的点、最右边的点、最左边的点,
        记录下这四个点,认为这是一个字符,然后在向后遍历点,直至找到黑色的点,继续以上的步骤
        最后通过每个字符的四个点进行切割
        '''
        # 各区块长度L列表
        zoneL = []
        # 各区块的X轴 [起始,终点]列表
        zoneWB = []
        # 各区块的Y轴 [起始,终点]列表
        zoneHB = []
        # 上一区块结束黑点横坐标,这里是初始化
        xmax = 0
        for i in range(10):
            try:
                x_fd, y_fd = detectFgPix(im, xmax)
                # print(y_fd, x_fd)
                xmax, xmin, ymax, ymin = cfs(im, x_fd, y_fd)
                L = xmax - xmin
                H = ymax - ymin
                zoneL.append(L)
                zoneWB.append([xmin, xmax])
                zoneHB.append([ymin, ymax])
            except TypeError:
                return zoneL, zoneWB, zoneHB
        return zoneL, zoneWB, zoneHB
    
    
    def cutting_img(im, im_position, img, xoffset=1, yoffset=1):
        filename = dir_path + '/out_img/' + img.split('.')[0]
        # 识别出的字符个数
        im_number = len(im_position[1])
        # 切割字符
        for i in range(im_number):
            im_start_X = im_position[1][i][0] - xoffset
            im_end_X = im_position[1][i][1] + xoffset
            im_start_Y = im_position[2][i][0] - yoffset
            im_end_Y = im_position[2][i][1] + yoffset
            cropped = im[im_start_Y:im_end_Y, im_start_X:im_end_X]
            cv2.imwrite(filename + '-cutting-' + str(i) + '.jpg',cropped)
    
    
    def main():
        filedir = dir_path + '/code_img'
        # pytesseract.pytesseract.tesseract_cmd='D:/Tesseract-OCR/tesseract.exe'
        for file in os.listdir(filedir):
            if fnmatch(file, '*.jpeg'):
                img_name = file
                # 自适应阈值二值化
                im = _get_dynamic_binary_image(filedir, img_name)
                # 去除边框
                im = clear_border(im, img_name)
                # 对图片进行干扰线降噪
                im = interference_line(im, img_name)
                # 对图片进行点降噪
                im = interference_point(im, img_name)
                # 切割的位置
                im_position = CFS(im)
                maxL = max(im_position[0])
                minL = min(im_position[0])
                # 如果有粘连字符,如果一个字符的长度过长就认为是粘连字符,并从中间进行切割
                num_val = minL + minL * 0.7
                if maxL > num_val:
                    maxL_index = im_position[0].index(maxL)
                    minL_index = im_position[0].index(minL)
                    # 设置字符的宽度
                    im_position[0][maxL_index] = maxL // 2
                    im_position[0].insert(maxL_index + 1, maxL // 2)
                    # 设置字符X轴 [起始,终点] 位置
                    im_position[1][maxL_index][1] = im_position[1][maxL_index][0] + maxL // 2
                    im_position[1].insert(maxL_index + 1,
                                          [im_position[1][maxL_index][1] + 1,
                                          im_position[1][maxL_index][1] + 1 + maxL // 2])
                    # 设置字符的Y轴 [起始,终点] 位置
                    im_position[2].insert(maxL_index + 1, im_position[2][maxL_index])
                # 切割字符,要想切得好就得配置参数,通常 1 or 2 就可以
                cutting_img(im, im_position,img_name, 1, 1)
                # 识别验证码
                cutting_img_num = 0
                for file in os.listdir(dir_path + '/out_img'):
                    str_img = ''
                    if fnmatch(file, '%s-cutting-*.jpg' % img_name.split('.')[0]):
                        cutting_img_num += 1
                for i in range(cutting_img_num):
                    try:
                        file = dir_path + '/out_img/%s-cutting-%s.jpg' % (img_name.split('.')[0], i)
                        # 识别验证码, 单个字符是10,一行文本是7
                        str_img = str_img + image_to_string(Image.open(file))
                    except Exception as err:
                        pass
                print('切图:%s' % cutting_img_num)
                print('识别为:%s' % str_img)
    
    
    if __name__ == '__main__':
        main()
    
    

    相关文章

      网友评论

          本文标题:图片处理

          本文链接:https://www.haomeiwen.com/subject/mlhtwctx.html