基于openCV数字图像与机器视觉(SVD特征值提取,检测硬币、细胞、条码)

一、比较不同位深度BMP文件

用图画板或其他图像编辑软件(Photoshop/GIMP、cximage、IrfanView等)打开一个彩色图像文件,将其分别保存为 32位、16位彩色和256色、16色、单色的位图(BMP)文件,对比其文件大小,并计算分析这些图片在内存中的存储容量是多少?当保存为BMP文件时,将用文件头来记录图像的属性,请问:BMP文件头是多大?是什么格式?上述5个类型的BMP的文件头内容有什么差异?

  1. 准备一张图片

在这里插入图片描述

位图文件头(BITMAPFILEHEADER)
位图文件头分4部分,共14字节:

名称占用空间内容实际数据
bfType2字节标识,就是“BM”二字BM
bfSize4字节整个BMP文件的大小0x000C0036(786486)
bfReserved1/24字节保留字,没用0
bfOffBits4字节偏移数,即 位图文件头+位图信息头+调色板 的大小
  1. 首先是32位图img32.bmp
    在这里插入图片描述

信息显示图片大小为189KB,位图大小计算:(分辨率)220×220×32/8/1024=189KB,这是不包含文件头信息的大小。
使用UltraEdit打开图片,查看文件头信息:
0x0002F478->193656
在这里插入图片描述

  1. 16位彩色图img12w.bmp
    在这里插入图片描述

信息显示图片大小为94.5kb,位图大小计算:220×220×16/8/1024=94.5KB,这是不包含文件头信息的大小。

使用UltraEdit打开图片,查看文件头信息:
0x00017A58->96856
在这里插入图片描述

  1. 256色位图img256.bmp
    在这里插入图片描述

信息显示图片大小为48.3KB,位图大小计算:220×220×8/8/1024=48.3KB,这是不包含文件头信息的大小。

使用UltraEdit打开图片,查看文件头信息:
在这里插入图片描述

  1. 16色位图img16.bmp
    在这里插入图片描述

信息显示图片大小为24.1KB,位图大小计算:220×220×4/8/1024=24.1KB,这是不包含文件头信息的大小。

使用UltraEdit打开图片,查看文件头信息:
在这里插入图片描述

  1. 单色位图img1.bmp
    在这里插入图片描述

信息显示图片大小为6.07KB,位图大小计算:220×220×1/8/1024=6.07KB,这是不包含文件头信息的大小。

使用UltraEdit打开图片,查看文件头信息:
在这里插入图片描述

二、不同图片格式的压缩比

比较大小:

原图PNG大小为89.6字节

BMP大小:768 字节,压缩比:-857%

JPG大小:75 字节,压缩比:83%

GIF大小:126 字节,压缩比:140%

也不知道为什么转换成不同格式是

三、用奇异值分解(SVD)进行特征值提取(降维)处理;

  1. 代码
import numpy as np
import os
from PIL import Image
import matplotlib.pyplot as plt
import matplotlib as mpl
from pprint import pprint


def restore1(sigma, u, v, K):  # 奇异值、左特征向量、右特征向量
    m = len(u)
    n = len(v[0])
    a = np.zeros((m, n))
    for k in range(K):
        uk = u[:, k].reshape(m, 1)
        vk = v[k].reshape(1, n)
        a += sigma[k] * np.dot(uk, vk)
    a[a < 0] = 0
    a[a > 255] = 255
    # a = a.clip(0, 255)
    return np.rint(a).astype('uint8')


def restore2(sigma, u, v, K):  # 奇异值、左特征向量、右特征向量
    m = len(u)
    n = len(v[0])
    a = np.zeros((m, n))
    for k in range(K+1):
        for i in range(m):
            a[i] += sigma[k] * u[i][k] * v[k]
    a[a < 0] = 0
    a[a > 255] = 255
    return np.rint(a).astype('uint8')


if __name__ == "__main__":
    A = Image.open("./pic/lean.png", 'r')
    print(A)
    output_path = r'./pic/SVD_Output'
    if not os.path.exists(output_path):
        os.mkdir(output_path)
    a = np.array(A)
    print(a.shape)
    K = 50
    u_r, sigma_r, v_r = np.linalg.svd(a[:, :, 0])
    u_g, sigma_g, v_g = np.linalg.svd(a[:, :, 1])
    u_b, sigma_b, v_b = np.linalg.svd(a[:, :, 2])
    plt.figure(figsize=(11, 9), facecolor='w')
    mpl.rcParams['font.sans-serif'] = ['simHei']
    mpl.rcParams['axes.unicode_minus'] = False
    for k in range(1, K+1):
        print(k)
        R = restore1(sigma_r, u_r, v_r, k)
        G = restore1(sigma_g, u_g, v_g, k)
        B = restore1(sigma_b, u_b, v_b, k)
        I = np.stack((R, G, B), axis=2)
        Image.fromarray(I).save('%s\\svd_%d.png' % (output_path, k))
        if k <= 12:
            plt.subplot(3, 4, k)
            plt.imshow(I)
            plt.axis('off')
            plt.title('奇异值个数:%d' % k)
    plt.suptitle('SVD与图像分解', fontsize=20)
    plt.tight_layout()
    # plt.subplots_adjust(top=0.9)
    plt.show()

  1. 部分截图:
    在这里插入图片描述

四、检测图像中硬币、细胞的个数。

在这里插入图片描述

代码

#!/usr/bin/env python3
# -*- coding: utf-8 -*-


"""
    项目主题:硬币检测和计数的设计与实现
"""
import cv2
import numpy as np


def stackImages(scale, imgArray):
    """
        将多张图像压入同一个窗口显示
        :param scale:float类型,输出图像显示百分比,控制缩放比例,0.5=图像分辨率缩小一半
        :param imgArray:元组嵌套列表,需要排列的图像矩阵
        :return:输出图像
    """
    rows = len(imgArray)
    cols = len(imgArray[0])
    rowsAvailable = isinstance(imgArray[0], list)
    width = imgArray[0][0].shape[1]
    height = imgArray[0][0].shape[0]
    if rowsAvailable:
        for x in range(0, rows):
            for y in range(0, cols):
                if imgArray[x][y].shape[:2] == imgArray[0][0].shape[:2]:
                    imgArray[x][y] = cv2.resize(imgArray[x][y], (0, 0), None, scale, scale)
                else:
                    imgArray[x][y] = cv2.resize(imgArray[x][y], (imgArray[0][0].shape[1], imgArray[0][0].shape[0]),
                                                None, scale, scale)
                if len(imgArray[x][y].shape) == 2: imgArray[x][y] = cv2.cvtColor(imgArray[x][y], cv2.COLOR_GRAY2BGR)
        imageBlank = np.zeros((height, width, 3), np.uint8)
        hor = [imageBlank] * rows
        hor_con = [imageBlank] * rows
        for x in range(0, rows):
            hor[x] = np.hstack(imgArray[x])
        ver = np.vstack(hor)
    else:
        for x in range(0, rows):
            if imgArray[x].shape[:2] == imgArray[0].shape[:2]:
                imgArray[x] = cv2.resize(imgArray[x], (0, 0), None, scale, scale)
            else:
                imgArray[x] = cv2.resize(imgArray[x], (imgArray[0].shape[1], imgArray[0].shape[0]), None, scale, scale)
            if len(imgArray[x].shape) == 2: imgArray[x] = cv2.cvtColor(imgArray[x], cv2.COLOR_GRAY2BGR)
        hor = np.hstack(imgArray)
        ver = hor
    return ver


'1. 初始操作'
src = cv2.imread("./pic/coin.png")
img = src.copy()

'2. 获得形态学变换的【结构元】——ELLIPSE=椭圆形  RECT=矩形   CROSS=交叉形'
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3))

'3. 腐蚀——erode()参数含义:1)原图    2)结构元   iterations=次数'
er = cv2.erode(img, kernel, iterations=1)

'4. 膨胀——dilate()参数含义:1)原图   3)结构元   iterations=次数'
di = cv2.dilate(er, kernel, iterations=5)

'5. 图像预处理——灰度化'
gray = cv2.cvtColor(di, cv2.COLOR_BGR2GRAY)

'6. 图像预处理——二值化'
ret, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)

'7. 图像预处理——消除特有噪声(形态学变换)'

dilate = cv2.morphologyEx(thresh, cv2.MORPH_DILATE, kernel, iterations=2)
opening = cv2.morphologyEx(dilate, cv2.MORPH_CLOSE, kernel, iterations=3)

'根据距离变换的性质,经过简单的运算,即可用于细化字符的轮廓和查找物体质心(中心)。'
'5. 寻找前景区域——分离连接物体distanceTranform()参数含义:1)二值图像     2)距离变换类型   3)距离变换的掩膜模板'
# DIST_L2:简单欧几里得距离 Δ = sqrt((x1 - x2)² + (y1 - y2)²)
dist_transform = cv2.distanceTransform(opening, cv2.DIST_L2, 3)

'6. 找到未知区域'
ret, sure_fg = cv2.threshold(dist_transform, 0.5 * dist_transform.max(), 255, 0)
print(ret)
sure_fg = np.uint8(sure_fg)

'7. 找到硬币中心(轮廓查找)findContours()参数含义:1)8位图像   2)轮廓查找模式    3)查找近似方法'
contours, hierarchy = cv2.findContours(sure_fg, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[-2:]

'8. 绘制硬币中心(轮廓绘制)drawContours()参数含义:1)原图     2)轮廓点坐标   3)轮廓索引    4)线条颜色  5)线条粗细'
cv2.drawContours(img, contours, -1, (0, 0, 255), 3)

'9. 完成显示'
'''
    *知识点回顾:
    putText()参数含义:1)图像  2)需显示的文本  3)坐标  4)文本字体  5)文本尺寸百分比   6)文本颜色   7)文本粗细
'''
cv2.putText(img, "count:{}".format(len(contours)), (0, 30), cv2.FONT_HERSHEY_SIMPLEX, 1.0, (0, 255, 0), 3)
cv2.putText(src, "srcImg", (0, 30), cv2.FONT_HERSHEY_SIMPLEX, 1.0, (0, 255, 0), 3)
cv2.putText(gray, "gray", (0, 30), cv2.FONT_HERSHEY_SIMPLEX, 1.0, (255, 255, 255), 3)
cv2.putText(thresh, "thresh", (0, 30), cv2.FONT_HERSHEY_SIMPLEX, 1.0, (255, 255, 255), 3)
cv2.putText(opening, "open", (0, 30), cv2.FONT_HERSHEY_SIMPLEX, 1.0, (255, 255, 255), 3)
cv2.putText(sure_fg, "fg", (0, 30), cv2.FONT_HERSHEY_SIMPLEX, 1.0, (255, 255, 255), 3)

imgStack = stackImages(0.7, ([src, gray, thresh], [opening, sure_fg, img]))
cv2.imshow("imgStack", imgStack)
cv2.waitKey(0)

在这里插入图片描述

细胞检测上同,不再重复
在这里插入图片描述

五、图片中的条形码检测与识别

在这里插入图片描述

代码

import cv2
import numpy as np
import imutils
from pyzbar import pyzbar
def stackImages(scale, imgArray):
    """
        将多张图像压入同一个窗口显示
        :param scale:float类型,输出图像显示百分比,控制缩放比例,0.5=图像分辨率缩小一半
        :param imgArray:元组嵌套列表,需要排列的图像矩阵
        :return:输出图像
    """
    rows = len(imgArray)
    cols = len(imgArray[0])
    rowsAvailable = isinstance(imgArray[0], list)
    width = imgArray[0][0].shape[1]
    height = imgArray[0][0].shape[0]
    if rowsAvailable:
        for x in range(0, rows):
            for y in range(0, cols):
                if imgArray[x][y].shape[:2] == imgArray[0][0].shape[:2]:
                    imgArray[x][y] = cv2.resize(imgArray[x][y], (0, 0), None, scale, scale)
                else:
                    imgArray[x][y] = cv2.resize(imgArray[x][y], (imgArray[0][0].shape[1], imgArray[0][0].shape[0]),
                                                None, scale, scale)
                if len(imgArray[x][y].shape) == 2: imgArray[x][y] = cv2.cvtColor(imgArray[x][y], cv2.COLOR_GRAY2BGR)
        imageBlank = np.zeros((height, width, 3), np.uint8)
        hor = [imageBlank] * rows
        hor_con = [imageBlank] * rows
        for x in range(0, rows):
            hor[x] = np.hstack(imgArray[x])
        ver = np.vstack(hor)
    else:
        for x in range(0, rows):
            if imgArray[x].shape[:2] == imgArray[0].shape[:2]:
                imgArray[x] = cv2.resize(imgArray[x], (0, 0), None, scale, scale)
            else:
                imgArray[x] = cv2.resize(imgArray[x], (imgArray[0].shape[1], imgArray[0].shape[0]), None, scale, scale)
            if len(imgArray[x].shape) == 2: imgArray[x] = cv2.cvtColor(imgArray[x], cv2.COLOR_GRAY2BGR)
        hor = np.hstack(imgArray)
        ver = hor
    return ver


#读取图片
src = cv2.imread("./pic/tiaoma.png")
img = src.copy()

#灰度
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

#高斯滤波
GSblurred = cv2.GaussianBlur(gray, (5, 5), 1)


#Sobel算子
sobel_x = cv2.Sobel(GSblurred, cv2.CV_64F, 1, 0, ksize=3)
sobel_y = cv2.Sobel(GSblurred, cv2.CV_64F, 0, 1, ksize=3)
sobel_x = cv2.convertScaleAbs(sobel_x)
sobel_y = cv2.convertScaleAbs(sobel_y)
sobel = cv2.addWeighted(sobel_x, 0.5, sobel_y, 0.5, 0)

#均值滤波,消除高频噪声 (8*8)像素块
blurred = cv2.blur(sobel, (5, 5))

#二值化
ret, thresh = cv2.threshold(blurred, 127, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)

#闭运算
kernel = np.ones((100, 100), int)
closed = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)

#开运算
kernel = np.ones((200, 200), int)
opening = cv2.morphologyEx(closed, cv2.MORPH_OPEN, kernel)

#绘制条形码区域
contours = cv2.findContours(opening, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours = imutils.grab_contours(contours)
c = sorted(contours, key = cv2.contourArea, reverse = True)[0]
rect = cv2.minAreaRect(c)
box = cv2.cv.BoxPoints(rect) if imutils.is_cv2() else cv2.boxPoints(rect)
box = np.int0(box)
cv2.drawContours(img, [box], -1, (0,255,0), 20)

#显示图片信息
cv2.putText(img, "results", (200, 200), cv2.FONT_HERSHEY_SIMPLEX, 10.0, (255, 0, 0), 30)
cv2.putText(gray, "gray", (200, 200), cv2.FONT_HERSHEY_SIMPLEX, 10.0, (255, 0, 0), 30)
cv2.putText(GSblurred, "GSblurred",(200, 200), cv2.FONT_HERSHEY_SIMPLEX, 10.0, (255, 0, 0), 30)
cv2.putText(sobel, "Sobel", (200, 200), cv2.FONT_HERSHEY_SIMPLEX, 10.0, (255, 0, 0), 30)
cv2.putText(blurred, "blur", (200, 200), cv2.FONT_HERSHEY_SIMPLEX, 10.0, (255, 0, 0), 30)
cv2.putText(thresh, "thresh", (200, 200), cv2.FONT_HERSHEY_SIMPLEX, 10.0, (255, 0, 0), 30)
cv2.putText(closed, "close", (200, 200), cv2.FONT_HERSHEY_SIMPLEX, 10.0, (255, 0, 0), 30)
cv2.putText(opening, "open", (200, 200), cv2.FONT_HERSHEY_SIMPLEX, 10.0, (255, 0, 0), 30)

#输出条形码
barcodes = pyzbar.decode(src)
for barcode in barcodes:
    barcodeData = barcode.data.decode("utf-8")
    cv2.putText(img, barcodeData, (25, 600), cv2.FONT_HERSHEY_SIMPLEX, 5.0, (0, 255, 0), 30)

#显示所有图片
imgStack = stackImages(0.1, ([gray, GSblurred,sobel,blurred],[thresh,closed,opening,img]))
cv2.imshow("imgStack", imgStack)
cv2.waitKey(0)

结果:
在这里插入图片描述

六、参考

https://blog.csdn.net/djj199301111/article/details/107616015

  • 0
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值