美文网首页
图片处理

图片处理

作者: 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()

相关文章

  • Plupload 七牛图片上传(二)

    图片基本处理 七牛提供了一些图片处理方式,比如: **图片基本处理 ** √ **图片瘦身 ** 图片高级处理 图...

  • PPT培训第二天

    一、总结 二、图片处理 1,图片边框 2,图片映像 3,图片柔光等图片处理 4,图片格式刷:其他图片同样处理 三、...

  • iOS 图片上传处理 图片压缩 图片处理

    提到从摄像头/相册获取图片是面向终端用户的,由用户去浏览并选择图片为程序使用。在这里,我们需要过UIImagePi...

  • IOS 图片上传处理 图片压缩 图片处理

    提到从摄像头/相册获取图片是面向终端用户的,由用户去浏览并选择图片为程序使用。在这里,我们需要过UIImagePi...

  • 图片处理

    头像图片处理,没有图片时将姓名的首字母显示到图片上 /*NSString *name = @"name";// ...

  • 图片处理

    图片缩放 图片转码

  • 图片处理

    图片流 前端所说的图片流就是读取本地图片,并在页面使用文件流的方式显示出来。 首先,我们简单说下文件上传的几种方式...

  • 图片处理

    1、旋转2、裁剪3、截取4、平铺 自由拉伸 等比例缩放 根据颜色生成图片 截取某个view视图 文字水印 图片水印...

  • 图片处理

    iOS中图片的加载、圆角、阴影实现方式多种多样,我们需着重考虑性能问题 视图阴影 圆角图片 注意:这种方法能够避免...

  • 图片处理

    图片处理:当拿到一个字符串的时候,不知道是url还是本地路径的时候,怎么正确的拿到字符串代表的图片urlStr:为...

网友评论

      本文标题:图片处理

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