对src文件夹的组织形式重新梳理;

pull/21/head
pbyhqr72x 3 years ago
parent 511857cafa
commit 5606aa936f

@ -1,2 +1,5 @@
# exercise_2
3rdparty为第三方库
doc放相关文档
src源代码
moderl为uml图

@ -0,0 +1,46 @@
import PIL.Image
import numpy
import os
import shutil
def sum_right(path):
img = PIL.Image.open(path)
array = numpy.array(img)
num = array.sum(axis=0)
print(type(num))
res_left = 0
res_right = 0
for i in range(256,512):
res_right += num[i]
print(res_right)
# if __name__ == '__main__':
# dir2 = r"C:\Users\xinluo\PycharmProjects\pythonProject\Camera Roll"
# dir1 = r"C:\Users\xinluo\PycharmProjects\pythonProject\Saved Pictures"
# names = os.listdir(dir1)
# n = len(names)
# print("文件数量",n)
# res = 0
# average_5 = 25565356
# average_25 = 26409377
# average_5_right = 10006019
# #average_tmp = (average_25+average_5)//2
# count = 0
# #show(os.path.join(dir1, "uni4F6C.png"))
# for i in range(n):
# #取图片
# img = PIL.Image.open(os.path.join(dir1,names[i]))
# file = os.path.join(dir1,names[i])
# rmfile = os.path.join(dir2,names[i])
# array = numpy.array(img)
# num = array.sum(axis=0)
# res_right = 0
# for i in range(256, 512):
# res_right += num[i]
# average_5_right += res_right/n
#
# if (res_right > average_5_right).all():
# shutil.copyfile(file, rmfile)
# os.remove(file)
# count += 1
# print(average_5_right)
# print(count)

@ -0,0 +1,27 @@
# -*- coding: UTF-8 -*-
import argparse
import cv2
import os
# 使用方法命令行cd到脚本所在文件夹python picture.py -i "图片路径"
#便历图片,合格则保存,不合格则删除
def variance_of_laplacian(image):
# 使用拉普拉斯算子提取图像边缘信息,计算边缘的平均方差
return cv2.Laplacian(image, cv2.CV_64F).var()
def read_path(file_pathname):
#遍历该目录下的所有图片文件
for filename in os.listdir(file_pathname):
print(filename)
image = cv2.imread(file_pathname+'/'+filename)
# 取图片的灰度通道
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
fm = variance_of_laplacian(gray)
# 如果得分比阈值低,认为是模糊
if fm < 100.0:
os.remove(file_pathname+'/'+filename)
#read_path(r"C:\Users\xinluo\PycharmProjects\pythonProject\Saved Pictures")
#print(os.getcwd())

@ -0,0 +1,274 @@
import logging
import os
import shutil
import PIL
from PyQt5 import QtCore, QtGui, QtWidgets
import numpy as np
import matplotlib
import sys
import cv2
from djitellopy import tello
import matplotlib.pyplot as plt
# matplotlib.figure 模块提供了顶层的Artist(图中的所有可见元素都是Artist的子类)它包含了所有的plot元素
from matplotlib.figure import Figure
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg # pyqt5的画布
import calib_RGB
import huidu_shuai,qingxi_shuai,xiangsu_shuai,video_to_photo
import argparse
class MyMatplotlibFigure(FigureCanvasQTAgg):
"""
创建一个画布类并把画布放到FigureCanvasQTAgg
"""
def __init__(self, width=10, heigh=10, dpi=100):
plt.rcParams['figure.facecolor'] = 'r' # 设置窗体颜色
plt.rcParams['axes.facecolor'] = 'b' # 设置绘图区颜色
self.width_ = width
self.heigh_ = heigh
self.dpi = dpi
self.figs = Figure(figsize=(self.width_, self.heigh_), dpi=self.dpi)
super(MyMatplotlibFigure, self).__init__(self.figs) # 在父类种激活self.fig 否则不能显示图像
#self.axes = self.figs.add_subplot(111,projection='3d')
fig = plt.figure()
#fig.suptitle('3D reconstructed', fontsize=16)
#self.axes = fig.gca(projection='3d')
self.axes=fig.add_subplot(111, projection='3d')
def mat_plot_drow_axes(self, t, s, l):
"""
用清除画布刷新的方法绘图
:return:
"""
self.axes.cla() # 清除绘图区
self.axes.spines['top'].set_visible(False) # 顶边界不可见
self.axes.spines['right'].set_visible(False) # 右边界不可见
# fig = plt.figure()
# fig.suptitle('3D reconstructed', fontsize=16)
# ax = plt.axes(projection='3d')
# 设置左、下边界在00处相交
# self.axes.spines['bottom'].set_position(('data', 0)) # 设置y轴线原点数据为 0
self.axes.spines['left'].set_position(('data', 0)) # 设置x轴线原点数据为 0
# self.axes.plot(t, s, l, 'b.')
# self.set_xlabel('x axis')
# self.set_ylabel('y axis')
# self.set_zlabel('z axis')
# self.view_init(elev=135, azim=90)
# plt.savefig('Reconstruction.jpg')
# plt.show()
# self.axes.plot(t, s, l, 'o-r', linewidth=0.5)
self.axes.scatter(t,s,l, 'b.')
#self.axes.plot_surface(t,s,l)
self.axes.set_xlabel('x axis')
self.axes.set_ylabel('y axis')
self.axes.set_zlabel('z axis')
self.axes.view_init(elev=135, azim=90)
plt.savefig('Reconstruction.jpg')
plt.show()
self.figs.canvas.draw() # 这里注意是画布重绘self.figs.canvas
self.figs.canvas.flush_events() # 画布刷新self.figs.canvas
class Ui_MainWindow(QtWidgets.QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.timer_camera = QtCore.QTimer()
self.cap = cv2.VideoCapture()
self.CAM_NUM = 0
self.set_ui()
self.slot_init()
def set_ui(self):
self.setWindowTitle('虚拟沙盘') # 标题
self.resize(1200, 800) # 窗口尺寸
#self.status = self.statusTip('虚拟沙盘3D建模系统') # 消息
#self.status.showMessage()
self.__layout_main = QtWidgets.QVBoxLayout()
self.__layout_fun_button = QtWidgets.QHBoxLayout()
self.__layout_data_show = QtWidgets.QHBoxLayout()
self.button_open_camera = QtWidgets.QPushButton('打开摄像头')
self.button_operate = QtWidgets.QPushButton('键盘控制')
self.button_takephoto = QtWidgets.QPushButton('视频转图片')
self.button_make = QtWidgets.QPushButton('建模')
self.button_close = QtWidgets.QPushButton('退出')
self.button_open_camera.setMinimumHeight(50)
self.button_close.setMinimumHeight(50)
self.button_operate.setMinimumHeight(50)
self.button_takephoto.setMinimumHeight(50)
self.button_make.setMinimumHeight(50)
self.button_open_camera.move(10, 100)
self.label_show_camera = QtWidgets.QLabel()
#self.label_show_camera.move(400,400)
self.label_show_camera.setFixedSize(841, 681)
self.__layout_fun_button.addWidget(self.button_open_camera)
self.__layout_fun_button.addWidget(self.button_operate)
self.__layout_fun_button.addWidget(self.button_takephoto)
self.__layout_fun_button.addWidget(self.button_make)
self.__layout_fun_button.addWidget(self.button_close)
self.__layout_main.addLayout(self.__layout_fun_button)
self.__layout_main.addWidget(self.label_show_camera)
self.setLayout(self.__layout_main)
##########################################
# 将信号与槽关联
#self.btn1.clicked.connect(self.onClick_Button)
#self.btn2.clicked.connect(self.showDialog)
def slot_init(self):
self.button_open_camera.clicked.connect(
self.button_open_camera_clicked)
self.timer_camera.timeout.connect(self.show_camera)
self.button_close.clicked.connect(self.onClick_Button)
self.button_make.clicked.connect(self.showDialog)
self.button_takephoto.clicked.connect(self.take_photo)
def take_photo(self):
#video to photo
args = video_to_photo.parse_args()
if not os.path.exists(args.output):
os.makedirs(args.output)
print('Called with args:')
print(args)
video_to_photo.process_video(args.input, args.output, args.skip_frame)
#灰度值筛选
dir2 = r"C:\Users\xinluo\PycharmProjects\pythonProject\Camera Roll"
dir1 = r"C:\Users\xinluo\PycharmProjects\pythonProject\Saved Pictures"
names = os.listdir(dir1)
n = len(names)
print("文件数量", n)
res = 0
average_5 = 25565356
average_25 = 26409377
average_5_right = 10006019
# average_tmp = (average_25+average_5)//2
count = 0
# show(os.path.join(dir1, "uni4F6C.png"))
for i in range(n):
# 取图片
print(1234)
img = PIL.Image.open(os.path.join(dir1, names[i]))
file = os.path.join(dir1, names[i])
rmfile = os.path.join(dir2, names[i])
array = np.array(img)
num = array.sum(axis=0)
res_right = 0
for i in range(256, 512):
res_right += num[i]
average_5_right += res_right / n
#res_right > average_5_right
if (1):
print(4321)
shutil.copyfile(file, rmfile)
os.remove(file)
count += 1
print(average_5_right)
print(count)
#像素筛选
xiangsu_shuai.pixel()
#清晰度筛选
qingxi_shuai.read_path(r"C:\Users\xinluo\PycharmProjects\pythonProject\Camera Roll")
def button_open_camera_clicked(self):
if self.timer_camera.isActive() == False:
flag = self.cap.open(self.CAM_NUM)
if flag == False:
msg = QtWidgets.QMessageBox.warning(self, 'warning', "请检查无人机是否连接正确", buttons=QtWidgets.QMessageBox.Ok)
else:
self.timer_camera.start(30)
self.button_open_camera.setText('关闭摄像头')
else:
self.timer_camera.stop()
self.cap.release()
self.label_show_camera.clear()
self.button_open_camera.setText('打开摄像头')
def show_camera(self):
self.Drone = tello.Tello() # 创建飞行器对象
self.Drone.connect() # 连接到飞行器
self.Drone.streamon() # 开启视频传输
self.Drone.LOGGER.setLevel(logging.ERROR) # 只显示错误信息
#sleep(5) # 等待视频初始化
#kp.init() # 初始化按键处理模块
flag,OriginalImage = self.Drone.get_frame_read()
#flag, self.image = self.cap.read()
show = cv2.resize(OriginalImage, (640, 480))
show = cv2.cvtColor(show, cv2.COLOR_BGR2RGB)
showImage = QtGui.QImage(show.data, show.shape[1], show.shape[0],
QtGui.QImage.Format_RGB888)
self.label_show_camera.setPixmap(QtGui.QPixmap.fromImage(showImage))
#getKeyboardInput(drone=Drone, speed=70, image=Image) # 按键控制
cv2.imshow("Drone Control Centre", OriginalImage)
def showDialog(self):
dialog = QtWidgets.QDialog()
dialog.resize(1800, 1600)
button = QtWidgets.QPushButton('储存', dialog)
button.clicked.connect(dialog.close)
button.move(1350, 750)
dialog.setWindowTitle('建模视图')
dialog.setWindowModality(QtCore.Qt.ApplicationModal)
dialog.label = QtWidgets.QLabel(dialog)
dialog.label.setGeometry(QtCore.QRect(0, 0, 800, 600))
# 实例化自定义画布类
dialog.canvas = MyMatplotlibFigure(width=5, heigh=4, dpi=100)
#dialog.plotcos()
# t = np.arange(0.0, 5.0, 0.01)
# s = np.cos(2 * np.pi * t)
# dialog.canvas.mat_plot_drow_axes(t, s)
# dialog.canvas.figs.suptitle("sin") # 设置标题
# 重建3D点
dialog.canvas.mat_plot_drow_axes(Points3D[0], Points3D[1], Points3D[2])
dialog.canvas.figs.suptitle("SanDCJ") # 设置标题
dialog.hboxlayout = QtWidgets.QHBoxLayout(dialog.label)
dialog.hboxlayout.addWidget(dialog.canvas)
#不展示dialog只看figure
#dialog.exec()
def onClick_Button(self):
sender = self.sender() #获得button
#print(sender.text() + '按钮被按下')
app = QtWidgets.QApplication.instance()
#退出程序
app.quit()
if __name__ == '__main__':
inter_corner_shape = (9, 6)
size_per_grid = 0.023
# 储存用来标定相机的照片,这里是为畸变的照片
img_dir = ".\\pic\\RGB_camera_calib_img_1"
img_type = "jpg"
# 储存标定相机之后的参数,应该相机的内外参数与畸变参数
CameraParam_Path = '.\\CameraParam.txt'
# 要重建的目标图片
Images_Path = 'SubstitutionCalibration_Image_1/*.jpg'
# 计算相机参数
calib_RGB.calib(inter_corner_shape, size_per_grid, img_dir, img_type, CameraParam_Path)
# 读取相机参数
config = calib_RGB.readfromfile(CameraParam_Path)
K = np.array(config['mtx'])
# 计算3D点
Points3D = calib_RGB.epipolar_geometric(Images_Path, K)
app = QtWidgets.QApplication(sys.argv)
ui = Ui_MainWindow()
ui.show()
sys.exit(app.exec_())

@ -0,0 +1,50 @@
import cv2
import argparse
import os
def parse_args():
"""
Parse input arguments
"""
parser = argparse.ArgumentParser(description='Process pic')
parser.add_argument('--input', help='video to process', dest='input', default=None, type=str)
parser.add_argument('--output', help='pic to store', dest='output', default=None, type=str)
# default为间隔多少帧截取一张图片
parser.add_argument('--skip_frame', dest='skip_frame', help='skip number of video', default=10, type=int)
# input为输入视频的路径 output为输出存放图片的路径
args = parser.parse_args(['--input', r'C:\Users\xinluo\PycharmProjects\pythonProject\1234.mp4', '--output', r'C:\Users\xinluo\PycharmProjects\pythonProject\Saved Pictures'])
return args
def process_video(i_video, o_video, num):
cap = cv2.VideoCapture(i_video)
num_frame = cap.get(cv2.CAP_PROP_FRAME_COUNT)
expand_name = '.jpg'
if not cap.isOpened():
print("Please check the path.")
cnt = 0
count = 0
while 1:
ret, frame = cap.read()
cnt += 1
# how
# many
# frame
# to
# cut
if cnt % num == 0:
count += 1
cv2.imwrite(os.path.join(o_video, str(count) + expand_name), frame)
if not ret:
break
if __name__ == '__main__':
args = parse_args()
if not os.path.exists(args.output):
os.makedirs(args.output)
print('Called with args:')
print(args)
process_video(args.input, args.output, args.skip_frame)

@ -0,0 +1,22 @@
import os
from PIL import Image, ImageFile
# ImageFile.LOAD_TRUNCATED_IMAGES = True #如果图片太大报错可以使用这个
def pixel():
b = 0
dir = r'C:\Users\xinluo\PycharmProjects\pythonProject\Camera Roll' # 需要处理的图片目录
files = os.listdir(dir) # 得到需要处理的所有图片
files.sort() # 对图片进行排序
for each_bmp in files: # 遍历图片,进行筛选
each_bmp_root = os.path.join(dir, each_bmp) # 得到每个图片路径
image = Image.open(each_bmp_root) # 打开每个图片
img = image.convert('RGB') # 转化成RGB其实图片大多都是RGB即使灰度图也不一定转RGB看需求
width = img.size[0] # 获取图像的宽和长
height = img.size[1]
if (width < 650) or (height < 650): # 判断图形尺寸有一条边小于600像素的直接删除
os.remove(each_bmp_root)

@ -1,90 +0,0 @@
# -*- coding: utf-8 -*-
"""
Homework: Calibrate the Camera with ZhangZhengyou Method.
Picture File Folder: ".\pic\IR_camera_calib_img", With Distort.
By YouZhiyuan 2019.11.18
"""
import os
import numpy as np
import cv2
import glob
def calib(inter_corner_shape, size_per_grid, img_dir,img_type):
# criteria: only for subpix calibration, which is not used here.
# criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)
w,h = inter_corner_shape
# cp_int: corner point in int form, save the coordinate of corner points in world sapce in 'int' form
# like (0,0,0), (1,0,0), (2,0,0) ....,(10,7,0).
cp_int = np.zeros((w*h,3), np.float32)
cp_int[:,:2] = np.mgrid[0:w,0:h].T.reshape(-1,2)
# cp_world: corner point in world space, save the coordinate of corner points in world space.
cp_world = cp_int*size_per_grid
obj_points = [] # the points in world space
img_points = [] # the points in image space (relevant to obj_points)
images = glob.glob(img_dir + os.sep + '**.' + img_type)
for fname in images:
img = cv2.imread(fname)
gray_img = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
# find the corners, cp_img: corner points in pixel space.
ret, cp_img = cv2.findChessboardCorners(gray_img, (w,h), None)
# if ret is True, save.
if ret == True:
# cv2.cornerSubPix(gray_img,cp_img,(11,11),(-1,-1),criteria)
obj_points.append(cp_world)
img_points.append(cp_img)
# view the corners
cv2.drawChessboardCorners(img, (w,h), cp_img, ret)
cv2.imshow('FoundCorners',img)
cv2.waitKey(1)
cv2.destroyAllWindows()
# calibrate the camera
ret, mat_inter, coff_dis, v_rot, v_trans = cv2.calibrateCamera(obj_points, img_points, gray_img.shape[::-1], None, None)
print (("ret:"),ret)
print (("internal matrix:\n"),mat_inter)
# in the form of (k_1,k_2,p_1,p_2,k_3)
print (("distortion cofficients:\n"),coff_dis)
print (("rotation vectors:\n"),v_rot)
print (("translation vectors:\n"),v_trans)
# calculate the error of reproject
total_error = 0
for i in range(len(obj_points)):
img_points_repro, _ = cv2.projectPoints(obj_points[i], v_rot[i], v_trans[i], mat_inter, coff_dis)
error = cv2.norm(img_points[i], img_points_repro, cv2.NORM_L2)/len(img_points_repro)
total_error += error
print(("Average Error of Reproject: "), total_error/len(obj_points))
return mat_inter, coff_dis
def dedistortion(inter_corner_shape, img_dir,img_type, save_dir, mat_inter, coff_dis):
w,h = inter_corner_shape
images = glob.glob(img_dir + os.sep + '**.' + img_type)
for fname in images:
img_name = fname.split(os.sep)[-1]
img = cv2.imread(fname)
newcameramtx, roi = cv2.getOptimalNewCameraMatrix(mat_inter,coff_dis,(w,h),0,(w,h)) # 自由比例参数
dst = cv2.undistort(img, mat_inter, coff_dis, None, newcameramtx)
# clip the image
# x,y,w,h = roi
# dst = dst[y:y+h, x:x+w]
cv2.imwrite(save_dir + os.sep + img_name, dst)
print('Dedistorted images have been saved to: %s successfully.' %save_dir)
if __name__ == '__main__':
inter_corner_shape = (11,8)
size_per_grid = 0.02
img_dir = ".\\pic\\IR_camera_calib_img"
img_type = "png"
# calibrate the camera
mat_inter, coff_dis = calib(inter_corner_shape, size_per_grid, img_dir,img_type)
# dedistort and save the dedistortion result.
save_dir = ".\\pic\\save_dedistortion"
if(not os.path.exists(save_dir)):
os.makedirs(save_dir)
dedistortion(inter_corner_shape, img_dir, img_type, save_dir, mat_inter, coff_dis)

@ -1,353 +0,0 @@
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'main.py'
#
# Created by: PyQt5 UI code generator 5.12.3
#
# WARNING! All changes made in this file will be lost!
import os
import cv2
import json
import numpy as np
import glob
from PIL import Image
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
def cart2hom(arr):
""" Convert catesian to homogenous points by appending a row of 1s
:param arr: array of shape (num_dimension x num_points)
:returns: array of shape ((num_dimension+1) x num_points)
"""
if arr.ndim == 1:
return np.hstack([arr, 1])
return np.asarray(np.vstack([arr, np.ones(arr.shape[1])]))
def compute_P_from_essential(E):
""" Compute the second camera matrix (assuming P1 = [I 0])
from an essential matrix. E = [t]R
:returns: list of 4 possible camera matrices.
"""
U, S, V = np.linalg.svd(E)
# Ensure rotation matrix are right-handed with positive determinant
if np.linalg.det(np.dot(U, V)) < 0:
V = -V
# create 4 possible camera matrices (Hartley p 258)
W = np.array([[0, -1, 0], [1, 0, 0], [0, 0, 1]])
P2s = [np.vstack((np.dot(U, np.dot(W, V)).T, U[:, 2])).T,
np.vstack((np.dot(U, np.dot(W, V)).T, -U[:, 2])).T,
np.vstack((np.dot(U, np.dot(W.T, V)).T, U[:, 2])).T,
np.vstack((np.dot(U, np.dot(W.T, V)).T, -U[:, 2])).T]
return P2s
def correspondence_matrix(p1, p2):
p1x, p1y = p1[:2]
p2x, p2y = p2[:2]
return np.array([
p1x * p2x, p1x * p2y, p1x,
p1y * p2x, p1y * p2y, p1y,
p2x, p2y, np.ones(len(p1x))
]).T
return np.array([
p2x * p1x, p2x * p1y, p2x,
p2y * p1x, p2y * p1y, p2y,
p1x, p1y, np.ones(len(p1x))
]).T
def scale_and_translate_points(points):
""" Scale and translate image points so that centroid of the points
are at the origin and avg distance to the origin is equal to sqrt(2).
:param points: array of homogenous point (3 x n)
:returns: array of same input shape and its normalization matrix
"""
x = points[0]
y = points[1]
center = points.mean(axis=1) # mean of each row
cx = x - center[0] # center the points
cy = y - center[1]
dist = np.sqrt(np.power(cx, 2) + np.power(cy, 2))
scale = np.sqrt(2) / dist.mean()
norm3d = np.array([
[scale, 0, -scale * center[0]],
[0, scale, -scale * center[1]],
[0, 0, 1]
])
return np.dot(norm3d, points), norm3d
def compute_image_to_image_matrix(x1, x2, compute_essential=False):
""" Compute the fundamental or essential matrix from corresponding points
(x1, x2 3*n arrays) using the 8 point algorithm.
Each row in the A matrix below is constructed as
[x'*x, x'*y, x', y'*x, y'*y, y', x, y, 1]
"""
A = correspondence_matrix(x1, x2)
# compute linear least square solution
U, S, V = np.linalg.svd(A)
F = V[-1].reshape(3, 3)
# constrain F. Make rank 2 by zeroing out last singular value
U, S, V = np.linalg.svd(F)
S[-1] = 0
if compute_essential:
S = [1, 1, 0] # Force rank 2 and equal eigenvalues
F = np.dot(U, np.dot(np.diag(S), V))
return F
def compute_normalized_image_to_image_matrix(p1, p2, compute_essential=False):
""" Computes the fundamental or essential matrix from corresponding points
using the normalized 8 point algorithm.
:input p1, p2: corresponding points with shape 3 x n
:returns: fundamental or essential matrix with shape 3 x 3
"""
n = p1.shape[1]
if p2.shape[1] != n:
raise ValueError('Number of points do not match.')
# preprocess image coordinates
p1n, T1 = scale_and_translate_points(p1)
p2n, T2 = scale_and_translate_points(p2)
# compute F or E with the coordinates
F = compute_image_to_image_matrix(p1n, p2n, compute_essential)
# reverse preprocessing of coordinates
# We know that P1' E P2 = 0
F = np.dot(T1.T, np.dot(F, T2))
return F / F[2, 2]
def compute_fundamental_normalized(p1, p2):
return compute_normalized_image_to_image_matrix(p1, p2)
def compute_essential_normalized(p1, p2):
return compute_normalized_image_to_image_matrix(p1, p2, compute_essential=True)
def skew(x):
""" Create a skew symmetric matrix *A* from a 3d vector *x*.
Property: np.cross(A, v) == np.dot(x, v)
:param x: 3d vector
:returns: 3 x 3 skew symmetric matrix from *x*
"""
return np.array([
[0, -x[2], x[1]],
[x[2], 0, -x[0]],
[-x[1], x[0], 0]
])
def reconstruct_one_point(pt1, pt2, m1, m2):
"""
pt1 and m1 * X are parallel and cross product = 0
pt1 x m1 * X = pt2 x m2 * X = 0
"""
A = np.vstack([
np.dot(skew(pt1), m1),
np.dot(skew(pt2), m2)
])
U, S, V = np.linalg.svd(A)
P = np.ravel(V[-1, :4])
return P / P[3]
def linear_triangulation(p1, p2, m1, m2):
"""
Linear triangulation (Hartley ch 12.2 pg 312) to find the 3D point X
where p1 = m1 * X and p2 = m2 * X. Solve AX = 0.
:param p1, p2: 2D points in homo. or catesian coordinates. Shape (3 x n)
:param m1, m2: Camera matrices associated with p1 and p2. Shape (3 x 4)
:returns: 4 x n homogenous 3d triangulated points
"""
num_points = p1.shape[1]
res = np.ones((4, num_points))
for i in range(num_points):
A = np.asarray([
(p1[0, i] * m1[2, :] - m1[0, :]),
(p1[1, i] * m1[2, :] - m1[1, :]),
(p2[0, i] * m2[2, :] - m2[0, :]),
(p2[1, i] * m2[2, :] - m2[1, :])
])
_, _, V = np.linalg.svd(A)
X = V[-1, :4]
res[:, i] = X / X[3]
return res
def writetofile(dict, path):
for index, item in enumerate(dict):
dict[item] = np.array(dict[item])
dict[item] = dict[item].tolist()
js = json.dumps(dict)
with open(path, 'w') as f:
f.write(js)
print("参数已成功保存到文件")
def readfromfile(path):
with open(path, 'r') as f:
js = f.read()
mydict = json.loads(js)
print("参数读取成功")
return mydict
def camera_calibration(SaveParamPath, ImagePath):
# 循环中断
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)
# 棋盘格尺寸
row = 11
column = 8
objpoint = np.zeros((row * column, 3), np.float32)
objpoint[:, :2] = np.mgrid[0:row, 0:column].T.reshape(-1, 2)
objpoints = [] # 3d point in real world space
imgpoints = [] # 2d points in image plane.
batch_images = glob.glob(ImagePath +os.sep+ '**.jpg')
for i, fname in enumerate(batch_images):
img = cv2.imread(batch_images[i])
imgGray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# find chess board corners
ret, corners = cv2.findChessboardCorners(imgGray, (row, column), None)
# if found, add object points, image points (after refining them)
if ret == True:
#objpoints.append(objpoint)
#corners2 = cv2.cornerSubPix(imgGray, corners, (11, 11), (-1, -1), criteria)
#imgpoints.append(corners2)
objpoints.append(objpoint)
imgpoints.append(corners)
# Draw and display the corners
img = cv2.drawChessboardCorners(img, (row, column), corners, ret)#corners
cv2.imwrite('Checkerboard_Image/Temp_JPG/Temp_' + str(i) + '.jpg', img)
print("成功提取:", len(batch_images), "张图片角点!")
ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, imgGray.shape[::-1], None, None)
dict = {'ret': ret, 'mtx': mtx, 'dist': dist, 'rvecs': rvecs, 'tvecs': tvecs}
writetofile(dict, SaveParamPath)
meanError = 0
for i in range(len(objpoints)):
imgpoints2, _ = cv2.projectPoints(objpoints[i], rvecs[i], tvecs[i], mtx, dist)
error = cv2.norm(imgpoints[i], imgpoints2, cv2.NORM_L2) / len(imgpoints2)
meanError += error
print("total error: ", meanError / len(objpoints))
def epipolar_geometric(Images_Path, K):
IMG = glob.glob(Images_Path)
img1, img2 = cv2.imread(IMG[0]), cv2.imread(IMG[1])
img1_gray = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)
img2_gray = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)
# Initiate SURF detector
SURF = cv2.xfeatures2d.SURF_create()
# compute keypoint & descriptions
keypoint1, descriptor1 = SURF.detectAndCompute(img1_gray, None)
keypoint2, descriptor2 = SURF.detectAndCompute(img2_gray, None)
print("角点数量:", len(keypoint1), len(keypoint2))
# Find point matches
bf = cv2.BFMatcher(cv2.NORM_L2, crossCheck=True)
matches = bf.match(descriptor1, descriptor2)
print("匹配点数量:", len(matches))
src_pts = np.asarray([keypoint1[m.queryIdx].pt for m in matches])
dst_pts = np.asarray([keypoint2[m.trainIdx].pt for m in matches])
# plot
knn_image = cv2.drawMatches(img1_gray, keypoint1, img2_gray, keypoint2, matches[:-1], None, flags=2)
image_ = Image.fromarray(np.uint8(knn_image))
image_.save("MatchesImage.jpg")
# Constrain matches to fit homography
retval, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, 100.0)
# We select only inlier points
points1 = src_pts[mask.ravel() == 1]
points2 = dst_pts[mask.ravel() == 1]
points1 = cart2hom(points1.T)
points2 = cart2hom(points2.T)
# plot
fig, ax = plt.subplots(1, 2)
ax[0].autoscale_view('tight')
ax[0].imshow(cv2.cvtColor(img1, cv2.COLOR_BGR2RGB))
ax[0].plot(points1[0], points1[1], 'r.')
ax[1].autoscale_view('tight')
ax[1].imshow(cv2.cvtColor(img2, cv2.COLOR_BGR2RGB))
ax[1].plot(points2[0], points2[1], 'r.')
plt.savefig('MatchesPoints.jpg')
fig.show()
#
points1n = np.dot(np.linalg.inv(K), points1)
points2n = np.dot(np.linalg.inv(K), points2)
E = compute_essential_normalized(points1n, points2n)
print('Computed essential matrix:', (-E / E[0][1]))
P1 = np.array([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0]])
P2s = compute_P_from_essential(E)
ind = -1
for i, P2 in enumerate(P2s):
# Find the correct camera parameters
d1 = reconstruct_one_point(points1n[:, 0], points2n[:, 0], P1, P2)
# Convert P2 from camera view to world view
P2_homogenous = np.linalg.inv(np.vstack([P2, [0, 0, 0, 1]]))
d2 = np.dot(P2_homogenous[:3, :4], d1)
if d1[2] > 0 and d2[2] > 0:
ind = i
P2 = np.linalg.inv(np.vstack([P2s[ind], [0, 0, 0, 1]]))[:3, :4]
Points3D = linear_triangulation(points1n, points2n, P1, P2)
return Points3D
def main():
CameraParam_Path = 'CameraParam.txt'
CheckerboardImage_Path = '.\\Checkerboard_Image'
Images_Path = 'SubstitutionCalibration_Image/*.jpg'
# 计算相机参数
camera_calibration(CameraParam_Path, CheckerboardImage_Path)
# 读取相机参数
config = readfromfile(CameraParam_Path)
K = np.array(config['mtx'])
# 计算3D点
Points3D = epipolar_geometric(Images_Path, K)
# 重建3D点
fig = plt.figure()
fig.suptitle('3D reconstructed', fontsize=16)
ax = fig.gca(projection='3d')
ax.plot(Points3D[0], Points3D[1], Points3D[2], 'b.')
ax.set_xlabel('x axis')
ax.set_ylabel('y axis')
ax.set_zlabel('z axis')
ax.view_init(elev=135, azim=90)
plt.savefig('Reconstruction.jpg')
plt.show()
if __name__ == '__main__':
main()

Before

Width:  |  Height:  |  Size: 292 KiB

After

Width:  |  Height:  |  Size: 292 KiB

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

@ -1 +1,9 @@
储存源代码
video文件夹储存着视频
Saved Pictures文件夹储存视频分帧之后得到的照片
Camera Roll文件夹储存照片经过灰度值、像素、清晰度三次筛选之后的照片
SubstitutionCalibration_Image_1文件夹储存将用来三维重建的照片
pic/RGB_camera_calib_img_1文件夹储存用来标定相机的棋盘照片照片为10*7大小边长2.1cm
output/CameraParam.txt储存标定相机之后得到的相机参数
output文件夹中三个照片分别为MatchesImage.jpg为匹配点对的连线图MatchesPoints.jpg为匹配点对图Reconstruction.jpg为初步尝试三维重建得到的三维点图。
SanDCJ中为主要代码video.py负责ui界面及和无人机连接calib_RGB.py实现三维重建video_to_photo.py实现视频提取照片huidu_shuai.py、qingxi_shuai.py、xiangsu_shuai.py分别为从灰度值、清晰度、像素三个方面筛选照片

@ -1,69 +0,0 @@
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
import numpy as np
import matplotlib
matplotlib.use("Qt5Agg") # 声明使用pyqt5
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg # pyqt5的画布
import matplotlib.pyplot as plt
# matplotlib.figure 模块提供了顶层的Artist(图中的所有可见元素都是Artist的子类)它包含了所有的plot元素
from matplotlib.figure import Figure
class MyMatplotlibFigure(FigureCanvasQTAgg):
"""
创建一个画布类并把画布放到FigureCanvasQTAgg
"""
def __init__(self, width=10, heigh=10, dpi=100):
plt.rcParams['figure.facecolor'] = 'r' # 设置窗体颜色
plt.rcParams['axes.facecolor'] = 'b' # 设置绘图区颜色
self.width_ = width
self.heigh_ = heigh
self.dpi = dpi
self.figs = Figure(figsize=(self.width_, self.heigh_), dpi=self.dpi)
super(MyMatplotlibFigure, self).__init__(self.figs) # 在父类种激活self.fig 否则不能显示图像
self.axes = self.figs.add_subplot(111)
def mat_plot_drow_axes(self, t, s):
"""
用清除画布刷新的方法绘图
:return:
"""
self.axes.cla() # 清除绘图区
self.axes.spines['top'].set_visible(False) # 顶边界不可见
self.axes.spines['right'].set_visible(False) # 右边界不可见
# 设置左、下边界在00处相交
# self.axes.spines['bottom'].set_position(('data', 0)) # 设置y轴线原点数据为 0
self.axes.spines['left'].set_position(('data', 0)) # 设置x轴线原点数据为 0
self.axes.plot(t, s, 'o-r', linewidth=0.5)
self.figs.canvas.draw() # 这里注意是画布重绘self.figs.canvas
self.figs.canvas.flush_events() # 画布刷新self.figs.canvas
class MainDialogImgBW_(QtWidgets.QMainWindow):
"""
创建UI主窗口使用画板类绘图
"""
def __init__(self):
super(MainDialogImgBW_, self).__init__()
self.setWindowTitle("显示matplotlib")
self.setObjectName("widget")
self.resize(800, 600)
self.label = QtWidgets.QLabel(self)
self.label.setGeometry(QtCore.QRect(0, 0, 800, 600))
#实例化自定义画布类
self.canvas = MyMatplotlibFigure(width=5, heigh=4, dpi=100)
self.plotcos()
self.hboxlayout = QtWidgets.QHBoxLayout(self.label)
self.hboxlayout.addWidget(self.canvas)
def plotcos(self):
# plt.clf()
t = np.arange(0.0, 5.0, 0.01)
s = np.cos(2 * np.pi * t)
self.canvas.mat_plot_drow_axes(t, s)
self.canvas.figs.suptitle("sin") # 设置标题
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
main = MainDialogImgBW_()
main.show()
sys.exit(app.exec_())

@ -1,45 +0,0 @@
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'untitled.ui'
#
# Created by: PyQt5 UI code generator 5.12.3
#
# WARNING! All changes made in this file will be lost!
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(800, 600)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.pushButton = QtWidgets.QPushButton(self.centralwidget)
self.pushButton.setGeometry(QtCore.QRect(110, 100, 56, 17))
self.pushButton.setObjectName("pushButton")
self.checkBox = QtWidgets.QCheckBox(self.centralwidget)
self.checkBox.setGeometry(QtCore.QRect(190, 100, 54, 13))
self.checkBox.setObjectName("checkBox")
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 18))
self.menubar.setObjectName("menubar")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.pushButton.setText(_translate("MainWindow", "PushButton"))
self.checkBox.setText(_translate("MainWindow", "CheckBox"))
class Ui_Form:
pass

@ -1,58 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<widget class="QPushButton" name="pushButton">
<property name="geometry">
<rect>
<x>110</x>
<y>100</y>
<width>56</width>
<height>17</height>
</rect>
</property>
<property name="text">
<string>PushButton</string>
</property>
</widget>
<widget class="QCheckBox" name="checkBox">
<property name="geometry">
<rect>
<x>190</x>
<y>100</y>
<width>54</width>
<height>13</height>
</rect>
</property>
<property name="text">
<string>CheckBox</string>
</property>
</widget>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>18</height>
</rect>
</property>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<resources/>
<connections/>
</ui>
Loading…
Cancel
Save