基于Visual studio+Opencv+Python的透视变换、图像处理(灰度化、二值化、Canny边缘检测)模型——以2015数学建模A题太阳影子定位为例

基于Visual studio+Opencv+Python的透视变换、图像处理(灰度化、二值化、Canny边缘检测)模型——以2015数学建模A题太阳影子定位为例

最近话少,较认真,闲言少叙。
2015A数学建模赛题(不完整)

如何确定视频的拍摄地点和拍摄日期是视频数据分析的重要方面,太阳影子定位技术就是通过分析视频中物体的太阳影子变化,确定视频拍摄的地点和日期的一种方法。
4.附件4为一根直杆在太阳下的影子变化的视频,并且已通过某种方式估计出直杆的高度为2米。请建立确定视频拍摄地点的数学模型,并应用你们的模型给出若干个可能的拍摄地点。
如果拍摄日期未知,你能否根据视频确定出拍摄地点与日期?

问题分析

原文附件中所给的视频格式是.avi格式,通过问题四我们可以了解到,本题解决问题关键在于如何从视频中提取关键要素(本题,不用前三题的结论与模型这题是做不出的。有了前三题的模型解本题相当简单,只需要将影长数据带入模型即可。当然这是在已经从视频提取影长信息后,才有的操作,简而言之,本题关键在于如何从视频提取需要的影长数据,这也是本文主要介绍的内容)。
视频提取关键帧,即截图,是最常见的手段之一,因为原始视频共有40min40s左右,所以可以以2min为分割点,提取截图,共有21张图片,随机可以用photoshop量尺工具量取影长,与杆长比例求解,即可得影长数据。
?????如果真的这样做的话,本文也就不存在,截图谁不会~~,我相信这也不是本题得初衷,先举一个例子:
在这里插入图片描述
在这里插入图片描述
这里有两张图片,已知笔长15cm,那从两张照片估算荧光笔得长度,哪一张图片估算的准确,第二张图片准确无疑,但是原理是什么,为什么第一张图存在这么大的误差?——透视畸变。
图像畸变对图片本身的影响
1.视频本身存在的透视畸变使影子投影到二维图像时出现距上的缩短
2.视频本身存在的拍摄角度倾斜问题会使截取一帧图像时产生梯形畸变

所涉及名词の解释

透视畸变&梯形畸变

透视畸变:
指图像使用二维方法表现三维的关系时,由于小孔成像原理,两平行线必在极远点相交,两平行线是用不可能相交的,图像会出现近大远小的现象,即发生畸变,如图4-4-1-1所示,不能准确刻画物体的准确特征。注意透视畸变是一种成像变形的现象,与我们平时所说的畸变产生原理不同,并不是我们平日里所说的畸变。
透视畸变在二维图像的表现(如下图)
Shapr3D
梯形畸变:
以摄像机一类数字设备拍摄目标物时,由于拍摄距离、角度等因素的限制,摄像头往往不方便垂直于地面(或被拍摄平面)获取图像,这样就产生了较大的畸变,使得图像质量下降给后续的图像处理带来影响,这种情况下,畸变主要包括径向畸变和倾斜畸变两种。
在倾斜畸变中,梯形畸变便是最常见的畸变之一。
透视变换(Perspective Transformation)
是指利用透视中心、像点、目标点三点共线的条件,按透视旋转定律使承影面(透视面)绕迹线(透视轴)旋转某一角度,破坏原有的投影光线束,仍能保持承影面上投影几何图形不变的变换,常用于图像的校正。
Opencv(Open Source Computer Vision Library)
是一个基于BSD许可(开源)发行的跨平台计算机视觉软件库,提供Python、MATLAB等语言接口,实现了图像处理与计算机视觉等高级通用算法。
Python
是一种计算机程序设计语言。是一种面向对象的动态类型语言,可以应用于图像处理、机器视觉等领域,是一种易读、易维护,并且被大量用户所欢迎的、用途广泛的编程语言。

基于Visual studio+Opencv+Python的逆透视图形变化处理(数学公式本文不再给出,怕过于冗长)

借助计算机辅助,在Visual studio平台上搭建Python开发环境,运行Opencv内置函数命令,对图像进行处理,即可得到矩阵A即透视变换矩阵,通过透视变换矩阵,借助编程,即可得到进行图像矫正后的图像,通过这种方法可以有效减少由于透视畸变与梯形畸变带来的图形处理误差。

视频处理

本文采用Opencv内置的函数cv2.VideoCapture(‘Appendix4.avi’)截取视频特定帧的画面(程序见附录四),并保存到指定文件夹下以备图像的处理操作。
因为附件一、二所给数据是21组,所以这里我们以2分钟作为一个分割点,一共导出21张光影图片。
视频处理代码:

import cv2
vc = cv2.VideoCapture('Appendix4.avi')  # 读入视频文件
f = 1
i = 1
if vc.isOpened():  # 判断是否正常打开
    rval, frame = vc.read()
else:
    rval = False
timeF = 25  # 视频帧计数间隔频率
while rval:  # 循环读取视频帧
    rval, frame = vc.read()
    if f % timeF == 0:  # 每隔timeF帧进行存储操作
        cv2.imwrite('D:\PYTHON\opencv_py\py_open\py_open\ ' + str(i) + '.jpg', frame)  # 存储为图像
        i = i + 1
        print("i:"+str(i)+',frame:'+str(f))
    f = f + 1
    cv2.waitKey(1)
vc.release()

图像预处理

透视变换图形处理

透视变换图形处理最重要的步骤是求出透视变化矩阵,具体计算公式在上文已经叙述,借助计算机编程算法得出透视变化矩阵:
在这里插入图片描述
借助Visual studio+Opencv编程(源程序见附录五)将截取的21张光影图片进行透视化处理并进行局部放大,结果如下图所示:
在这里插入图片描述
由图4-4-3-1可知,透视变换对处理由于图片摄像角度不正确、存在透视畸变等缺陷而造成的一系列图像问题,有很好的效果。
透视变换代码

import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread('hyq.jpg')
rows, cols = img.shape[:2]
# 原图中书本的四个角点
pts1 = np.float32([[700, 100], [2000, 100], [700, 1000], [2000, 1000]])
# 变换后分别在左上、右上、左下、右下四个点
pts2 = np.float32([[0, 0], [2000, 0], [0, 1000], [2000, 1000]])
# 生成透视变换矩阵
M = cv2.getPerspectiveTransform(pts1, pts2)
# 进行透视变换
dst = cv2.warpPerspective(img, M, (1800, 1000))
plt.subplot(121), plt.imshow(img[:, :, ::-1]), plt.title('input')
plt.subplot(122), plt.imshow(dst[:, :, ::-1]), plt.title('output')
# img[:, :, ::-1]是将BGR转化为RGB
#cv2.imwrite('20_20.jpg', dst)
cv2.namedWindow('hyq1',0)
cv2.imshow("hyq1", dst)
plt.show()
cv2.waitKey(0)
cv2.destroyAllWindows()
灰度化处理

将彩色图像转化成为灰度图像的过程成为图像的灰度化处理,其仍然反映了整幅图像的整体和局部的色度和亮度等级的分布和特征。
根据RGB和YUV颜色空间的变化关系可建立亮度Y与R、G、B三个颜色分量的对应关系:

灰色变换示意图
灰色处理代码

import cv2
import numpy as np

if __name__ == "__main__":
    img_path = "11_11.jpg"
    img = cv2.imread(img_path)
    #获取图片的宽和高
    width,height = img.shape[:2][::-1]
    #将图片缩小便于显示观看
    img_resize = cv2.resize(img,
    (int(width*0.5),int(height*0.5)),interpolation=cv2.INTER_CUBIC)
    #cv2.namedWindow('img',0)
    #cv2.imshow("img",img_resize)
    print("img_reisze shape:{}".format(np.shape(img_resize)))

    #将图片转为灰度图
    img_gray = cv2.cvtColor(img_resize,cv2.COLOR_RGB2GRAY)
    #cv2.namedWindow('img_gray',0)
    #cv2.imshow("img_gray",img_gray)
    cv2.imwrite('Grey_11.jpg', img_gray)
    print("img_gray shape:{}".format(np.shape(img_gray)))
    cv2.waitKey()
二值化处理

二值化是图像分割的一种最简单的方法,二值化可以把灰度图像转换成二值图像。把大于某个临界灰度值(阈值)的像素灰度设为灰度极大值(255),把小于这个值的像素灰度设为灰度极小值(0),从而更有利于做图像处理判别。
二值化分为固定阈值和自适应阈值,本题采用自适应赋值方法,借助Opencv编程得到二值化图像如下图

在这里插入图片描述
二值化代码

import cv2 as cv
import numpy as np
# 根据选定的方法自动寻找阈值
src = cv.imread('Grey_20.jpg')
def threshold_demo(image):
    # 灰度图像
    gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
    # 二值图像
    ret, binary = cv.threshold(gray, 0, 255, cv.THRESH_BINARY | cv.THRESH_TRIANGLE)
    print('threshold value %s' % ret)
    cv.imshow('binary', binary)
    
# 局部阈值
def local_threshold(image):
    gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
    # blockSize 必须是奇数,下面设为25, 比均值大10(自己设置)就设置为黑色或者白色,在10之内的设置为另一个颜色
    dst = cv.adaptiveThreshold(gray, 255, cv.ADAPTIVE_THRESH_GAUSSIAN_C, cv.THRESH_BINARY, 25, 10)
    #cv.imshow('binary', dst) 
    cv.imwrite('Grey_20.jpg', dst)
# 自适应阈值
def custom_threshold(image):
    gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
    h, w = gray.shape[:2]
    m = np.reshape(gray, [1, w*h])
    # 均值
    mean = m.sum() / (w*h)
    print('mean:', mean)
    ret, binary = cv.threshold(gray, mean, 255, cv.THRESH_BINARY)
    cv.imshow('binary', binary) 
# 手动设定阈值
def threshold_demo_1(image):
    gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
    ret, binary = cv.threshold(gray, 127, 255, cv.THRESH_TRUNC)
    print('threshold value %s' % ret)
    cv.imshow('binary', binary) 

#cv.namedWindow('input image', cv.WINDOW_AUTOSIZE)
#cv.imshow('input image', src)
local_threshold(src)
cv.waitKey(0)
cv.destroyAllWindows()
Canny边缘检测

Canny边缘检测是从不同视觉对象中提取有用的结构信息并大大减少要处理的数据量的一种技术,其边缘检测算法处理流程主要有包括:
1. 使用高斯滤波器,以平滑图像,滤除噪声
2. 计算图像中每个像素点的梯度强度和方向。
3. 应用非极大值抑制,以消除边缘检测带来的杂散响应。
4. 应用双阈值检测来确定真实的和潜在的边缘。
5. 通过抑制孤立的弱边缘最终完成边缘检测。
其中,阈值的选取是否得决定着图像是否具有连续性,本文采用动态赋予阈值的方法,通过Opencv编程得到Canny边缘检测结果。
在这里插入图片描述
代码如下

import cv2
import numpy as np 
def CannyThreshold(lowThreshold):
    detected_edges = cv2.GaussianBlur(gray,(3,3),0)
    detected_edges = cv2.Canny(detected_edges,lowThreshold,lowThreshold*ratio,apertureSize = kernel_size)
    dst = cv2.bitwise_and(img,img,mask = detected_edges)  # just add some colours to edges from original image.
    cv2.imshow('canny demo',dst)
    cv2.imwrite('Canny_20.jpg', dst)
lowThreshold = 0
max_lowThreshold = 100
ratio = 3
kernel_size = 3 
img = cv2.imread('Grey_20.jpg')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
cv2.namedWindow('canny demo')
cv2.createTrackbar('Min threshold','canny demo',lowThreshold, max_lowThreshold, CannyThreshold) 
CannyThreshold(0)  # initialization
if cv2.waitKey(0) == 27:
    cv2.destroyAllWindows()

模型的求解

数字图像处理过程始终能保持图像的再现,能够将我们所需要测量的区域加强并突显出来。
为便于计算与记录,本文将处理过的21组图像数据进行编排,生成excel表格(附录九),将杆高与影长数据带入问题二、三的数学模型进行求解,可得到附件四中的具体地理位置。

参考文献:

【1】张宇.数字图像梯形畸变校正算法研究与视频实时校正应用[D].安徽:安徽大学,2014:4-12
【2】张宇,张春燕,陈笋.基于OpenCV的视频图像梯形畸变实时校正方法[D].安徽:安徽大学科学学院,2013:43-47
【3】Daetalus.OpenCV-Python教程(8、Canny边缘检测)[Z].@CSDN,2013.
【4】The_Matrix_.图像透视变换原理及实现[Z].@CSDN,2018.

作者的话:

本文所用全部程序与图片均为自制,转载请注明出处,不胜感激。

  • 6
    点赞
  • 45
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值