第一次提交

1、hpi的可用代码;
2、修复了多次点击曝光后,福亮度数据错误的问题;
3、定标方式为大的蓝菲积分球的标准能量曲线,而不是基于asd的能量曲线;
This commit is contained in:
tangchao0503
2022-09-06 22:54:14 +08:00
commit 98cf134cca
106 changed files with 39400 additions and 0 deletions

0
library/__init__.py Normal file
View File

514
library/config.py Normal file
View File

@ -0,0 +1,514 @@
# 标准库
import traceback, os
# 三方库
import configparser
from PyQt5.QtCore import QObject, pyqtSignal
# 自己写的库
from library.dir_manager import DirManager
# class ConfigFile():
# def __init__(self):
# self.base_dir = get_path()
#
# self.log_dir = self.base_dir + '//log'
# self.create_directory(self.log_dir)
#
# self.corning_config_file = self.log_dir + '//corning_config.ini'
#
# self.read_config_file()
#
# self.signals = WorkerSignals()
# self.signals.image_signal.connect(self.image_record_param_changed)
# self.signals.spectral_signal.connect(self.spectral_record_param_changed)
#
#
# # 查看是否存在保存光谱和影像文件的目录,如果没有就创建
# def create_directory(self, directory):
# if not os.path.exists(directory):
# print('创建文件夹:', directory)
# os.makedirs(directory)
#
# # 读取配置文件,如果没有就创建
# def read_config_file(self):
# if os.path.exists(self.corning_config_file):
# '''
# 如果存在配置文件,就从配置文件中读取软件配置信息
# '''
# print('配置文件存在!')
#
# config = configparser.ConfigParser()
# config.read(self.corning_config_file)
#
# self.image_dir = config.get('image_record_param', 'image_dir')
# self.create_directory(self.image_dir)
# self.default_image_name = config.get('image_record_param', 'default_image_name')
# self.framerate = int(config.get('image_record_param', 'framerate'))
# self.exposure_time = int(config.get('image_record_param', 'exposure_time'))
# self.gain = int(float(config.get('image_record_param', 'gain')))
# self.frame_number = int(config.get('image_record_param', 'frame_number'))
#
# self.spectral_dir = config.get('spectral_record_param', 'spectral_dir')
# self.create_directory(self.spectral_dir)
# self.default_spectral_name = config.get('spectral_record_param', 'default_spectral_name')
#
# self.binning = int(config.get('bin', 'binning'))
# if self.binning == 1:
# self.start_column = int(config.get('bin', 'start_column_binning_1'))
# self.end_column = int(config.get('bin', 'end_column_binning_1'))
# self.start_row = int(config.get('bin', 'start_row_binning_1'))
# self.end_row = int(config.get('bin', 'end_row_binning_1'))
# elif self.binning == 2:
# self.start_column = int(config.get('bin', 'start_column_binning_2'))
# self.end_column = int(config.get('bin', 'end_column_binning_2'))
# self.start_row = int(config.get('bin', 'start_row_binning_2'))
# self.end_row = int(config.get('bin', 'end_row_binning_2'))
#
# # print(self.default_dir, self.binning, self.start_column, self.end_column, self.start_row, self.end_row)
#
# else:
# '''
# 1、如果不存在配置文件就建立配置文件
# 2、并且手动创建配置变量
# '''
# config = configparser.ConfigParser()
#
# # config.add_section('effective_window')
# # startRow = 339
# # endRow = 639
# # startColumn = 285
# # endColumn = 1649
#
#
# config.add_section('bin')
# config.set('bin', 'binning', '1')
#
# config.set('bin', 'start_column_binning_1', '12')
# config.set('bin', 'end_column_binning_1', '1376')
# config.set('bin', 'start_row_binning_1', '1')
# config.set('bin', 'end_row_binning_1', '301')
#
# config.set('bin', 'start_column_binning_2', '13')
# config.set('bin', 'end_column_binning_2', '695')
# config.set('bin', 'start_row_binning_2', '1')
# config.set('bin', 'end_row_binning_2', '150')
#
# config.add_section('image_record_param')
# config.set('image_record_param', 'image_dir', self.base_dir + '/image')
# config.set('image_record_param', 'default_image_name', 'testimage')
# config.set('image_record_param', 'framerate', '20')
# config.set('image_record_param', 'exposure_time', '500')
# config.set('image_record_param', 'gain', '0')
# config.set('image_record_param', 'frame_number', '20')
#
# config.add_section('spectral_record_param')
# config.set('spectral_record_param', 'spectral_dir', self.base_dir + '/spectral')
# config.set('spectral_record_param', 'default_spectral_name', 'testspectral')
# # config.set('spectral_record_param', 'start_column_binning_1', '12')
#
# with open(self.corning_config_file, mode='w') as f:
# config.write(f)
# print('创建配置文件成功!')
#
# # 如果没有配置文件,就手动创建配置变量
# self.image_dir = self.base_dir + '/image'
# self.create_directory(self.image_dir)
# self.default_image_name = 'testimage'
# self.framerate = 20
# self.exposure_time = 500
# self.gain = 0
# self.frame_number = 20
#
# self.spectral_dir = self.base_dir + '/spectral'
# self.create_directory(self.spectral_dir)
# self.default_spectral_name = 'testspectral'
#
# self.binning = int(config.get('bin', 'binning'))
# self.start_column = int(config.get('bin', 'start_column_binning_1'))
# self.end_column = int(config.get('bin', 'end_column_binning_1'))
# self.start_row = int(config.get('bin', 'start_row_binning_1'))
# self.end_row = int(config.get('bin', 'end_row_binning_1'))
#
# # self.start_column = 12
# # self.end_column = 1376
# # self.start_row = 1
# # self.end_row = 300
#
# def image_record_param_changed(self, dictionary):
# '''
# :param dictionary: {'image_dir':值, 'image_record_param': 值}
# :return:
# '''
# try:
# # print('接收的参数个数:', len(dictionary.keys()))
#
# config = configparser.ConfigParser()
# config.read(self.corning_config_file)
#
# for key in dictionary.keys():
# if key == 'image_dir':
# self.image_dir = dictionary[key]
# config.set('image_record_param', key, dictionary[key])
# if key == 'default_image_name':
# self.default_image_name = dictionary[key]
# config.set('image_record_param', key, dictionary[key])
# if key == 'framerate':
# self.framerate = dictionary[key]
# config.set('image_record_param', key, str(dictionary[key]))
# if key == 'exposure_time':
# self.exposure_time = dictionary[key]
# config.set('image_record_param', key, str(dictionary[key]))
# if key == 'gain':
# self.gain = dictionary[key]
# config.set('image_record_param', key, str(dictionary[key]))
# if key == 'frame_number':
# self.frame_number = dictionary[key]
# config.set('image_record_param', key, str(dictionary[key]))
# except:
# traceback.print_exc()
#
# with open(self.corning_config_file, 'w') as f:
# config.write(f)
#
# def spectral_record_param_changed(self, dictionary):
# '''
# :param dictionary: {'image_dir':值, 'image_record_param': 值}
# :return:
# '''
# print(len(dictionary.keys()))
#
# config = configparser.ConfigParser()
# config.read(self.corning_config_file)
#
# try:
# for key in dictionary.keys():
# if key == 'spectral_dir':
# self.spectral_dir = dictionary[key]
# config.set('spectral_record_param', key, dictionary[key])
# if key == 'default_spectral_name':
# self.default_spectral_name = dictionary[key]
# config.set('spectral_record_param', key, dictionary[key])
# except:
# traceback.print_exc()
#
# with open(self.corning_config_file, 'w') as f:
# config.write(f)
class ConfigFile(QObject, DirManager):
# 信号必须定义为类属性不能放在__init__方法里
image_signal = pyqtSignal(dict)
spectral_signal = pyqtSignal(dict)
def __init__(self):
'''
配置文件读取和写入类,采集数据需要的帧率、曝光、帧数、文件名等等都由此类从文件中读取并保存在此类中,
'''
super(ConfigFile, self).__init__()
self.corning_config_file = self.log_dir + '//corning_config.ini'
self.read_config_file()
self.image_signal.connect(self.image_record_param_changed)
self.spectral_signal.connect(self.spectral_record_param_changed)
# 读取配置文件,如果没有就创建
def read_config_file(self):
if os.path.exists(self.corning_config_file):
'''
如果存在配置文件,就从配置文件中读取软件配置信息
'''
print('配置文件存在!')
config = configparser.ConfigParser()
config.read(self.corning_config_file)
# self.image_dir = config.get('image_record_param', 'image_dir')
# self.create_directory(self.image_dir)
# self.default_image_name = config.get('image_record_param', 'default_image_name')
# self.framerate = int(config.get('image_record_param', 'framerate'))
# self.exposure_time = int(float(config.get('image_record_param', 'exposure_time')))
# self.gain = int(float(config.get('image_record_param', 'gain')))
# self.frame_number = int(config.get('image_record_param', 'frame_number'))
# self.arcus_speed = int(config.get('image_record_param', 'arcus_speed'))
#
# self.spectral_dir = config.get('spectral_record_param', 'spectral_dir')
# self.create_directory(self.spectral_dir)
# self.default_spectral_name = config.get('spectral_record_param', 'default_spectral_name')
# self.spectral_number = int(config.get('spectral_record_param', 'spectral_number'))
# self.framenumber_average = int(config.get('spectral_record_param', 'framenumber_average'))
# self.exposure_time_spectral = int(config.get('spectral_record_param', 'exposure_time_spectral'))
#
# self.binning = int(config.get('bin', 'binning'))
# if self.binning == 1:
# self.start_column = int(config.get('bin', 'start_column_binning_1'))
# self.end_column = int(config.get('bin', 'end_column_binning_1'))
# self.start_row = int(config.get('bin', 'start_row_binning_1'))
# self.end_row = int(config.get('bin', 'end_row_binning_1'))
# elif self.binning == 2:
# self.start_column = int(config.get('bin', 'start_column_binning_2'))
# self.end_column = int(config.get('bin', 'end_column_binning_2'))
# self.start_row = int(config.get('bin', 'start_row_binning_2'))
# self.end_row = int(config.get('bin', 'end_row_binning_2'))
#
# # print(self.default_dir, self.binning, self.start_column, self.end_column, self.start_row, self.end_row)
else:
'''
1、如果不存在配置文件就建立配置文件
2、并且手动创建配置变量
'''
config = configparser.ConfigParser()
config.add_section('bin')
config.set('bin', 'binning', '1')
# # Serial number = 008
# config.set('bin', 'start_column_binning_1', '12')
# config.set('bin', 'end_column_binning_1', '1376')
# config.set('bin', 'start_row_binning_1', '2')
# config.set('bin', 'end_row_binning_1', '302')
#
# config.set('bin', 'start_column_binning_2', '13')
# config.set('bin', 'end_column_binning_2', '695')
# config.set('bin', 'start_row_binning_2', '0')
# config.set('bin', 'end_row_binning_2', '150')
# # Serial number = 0073
# config.set('bin', 'start_column_binning_1', '12')
# config.set('bin', 'end_column_binning_1', '1376')
# config.set('bin', 'start_row_binning_1', '1')
# config.set('bin', 'end_row_binning_1', '301')
#
# config.set('bin', 'start_column_binning_2', '13')
# config.set('bin', 'end_column_binning_2', '695')
# config.set('bin', 'start_row_binning_2', '0')
# config.set('bin', 'end_row_binning_2', '150')
# # Serial number = 0095
# config.set('bin', 'start_column_binning_1', '12')
# config.set('bin', 'end_column_binning_1', '1376')
# config.set('bin', 'start_row_binning_1', '1')
# config.set('bin', 'end_row_binning_1', '301')
#
# config.set('bin', 'start_column_binning_2', '13')
# config.set('bin', 'end_column_binning_2', '695')
# config.set('bin', 'start_row_binning_2', '0')
# config.set('bin', 'end_row_binning_2', '150')
# Serial number = 0031
config.set('bin', 'start_column_binning_1', '12')
config.set('bin', 'end_column_binning_1', '1376')
config.set('bin', 'start_row_binning_1', '1')
config.set('bin', 'end_row_binning_1', '301')
config.set('bin', 'start_column_binning_2', '13')
config.set('bin', 'end_column_binning_2', '695')
config.set('bin', 'start_row_binning_2', '1')
config.set('bin', 'end_row_binning_2', '151')
# # Serial number = 0099
# config.set('bin', 'start_column_binning_1', '12')
# config.set('bin', 'end_column_binning_1', '1376')
# config.set('bin', 'start_row_binning_1', '1')
# config.set('bin', 'end_row_binning_1', '301')
#
# config.set('bin', 'start_column_binning_2', '13')
# config.set('bin', 'end_column_binning_2', '695')
# config.set('bin', 'start_row_binning_2', '1')
# config.set('bin', 'end_row_binning_2', '151')
config.add_section('effective_window')
config.set('effective_window', 'width_binning_1', '1392')
config.set('effective_window', 'offsetX_binning_1', '272')
config.set('effective_window', 'height_binning_1', '302')
config.set('effective_window', 'offsetY_binning_1', '364')
config.set('effective_window', 'width_binning_2', '696')
config.set('effective_window', 'offsetX_binning_2', '128')
config.set('effective_window', 'height_binning_2', '151')
config.set('effective_window', 'offsetY_binning_2', '182')
config.add_section('calibration_file')
config.set('calibration_file', 'cal_file_name_image_bining_1', 'lens_bin1_gain_SN0073')
config.set('calibration_file', 'cal_file_name_image_bining_2', 'lens_bin2_gain_SN0073')
config.set('calibration_file', 'cal_file_it_image_bining_1', '6969')
config.set('calibration_file', 'cal_file_it_image_bining_2', '1628')
config.set('calibration_file', 'cal_file_name_spectral_bining_1', 'optical_fiber_bin1_gain_SN0073')
config.set('calibration_file', 'cal_file_it_spectrl_bining_1', '42300')
config.add_section('wavelength_file_name')
config.set('wavelength_file_name', 'file_name', 'wavelength0073.txt')
config.add_section('image_record_param')
config.set('image_record_param', 'image_dir', self.base_dir + '/image')
config.set('image_record_param', 'default_image_name', 'testimage')
config.set('image_record_param', 'framerate', '20')
config.set('image_record_param', 'exposure_time', '500')
config.set('image_record_param', 'gain', '0')
config.set('image_record_param', 'frame_number', '20')
config.set('image_record_param', 'arcus_speed', '1000')
config.add_section('spectral_record_param')
config.set('spectral_record_param', 'spectral_dir', self.base_dir + '/spectral')
config.set('spectral_record_param', 'default_spectral_name', 'testspectral')
config.set('spectral_record_param', 'spectral_number', '10')
config.set('spectral_record_param', 'framenumber_average', '10')
config.set('spectral_record_param', 'exposure_time_spectral', '1000')
# config.set('spectral_record_param', 'start_column_binning_1', '12')
with open(self.corning_config_file, mode='w') as f:
config.write(f)# 如果没有配置文件,就手动创建配置变量
print('创建配置文件成功!')
# 读取配置文件中的参数
self.binning = int(config.get('bin', 'binning'))
print('读取配置文件中参数:', self.binning)
if self.binning == 1:
self.effective_window_width = int(config.get('effective_window', 'width_binning_1'))
self.effective_window_offsetx = int(config.get('effective_window', 'offsetx_binning_1'))
self.effective_window_height = int(config.get('effective_window', 'height_binning_1'))
self.effective_window_offsety = int(config.get('effective_window', 'offsety_binning_1'))
self.start_column = int(config.get('bin', 'start_column_binning_1'))
self.end_column = int(config.get('bin', 'end_column_binning_1'))
self.start_row = int(config.get('bin', 'start_row_binning_1'))
self.end_row = int(config.get('bin', 'end_row_binning_1'))
self.calibration_file_name_image=config.get('calibration_file', 'cal_file_name_image_bining_1')
self.calibration_file_it_image = int(config.get('calibration_file', 'cal_file_it_image_bining_1'))
self.calibration_file_name_spectral = config.get('calibration_file', 'cal_file_name_spectral_bining_1')
self.calibration_file_it_spectral = int(config.get('calibration_file', 'cal_file_it_spectrl_bining_1'))
elif self.binning == 2:
self.effective_window_width = int(config.get('effective_window', 'width_binning_2'))
self.effective_window_offsetx = int(config.get('effective_window', 'offsetx_binning_2'))
self.effective_window_height = int(config.get('effective_window', 'height_binning_2'))
self.effective_window_offsety = int(config.get('effective_window', 'offsety_binning_2'))
self.start_column = int(config.get('bin', 'start_column_binning_2'))
self.end_column = int(config.get('bin', 'end_column_binning_2'))
self.start_row = int(config.get('bin', 'start_row_binning_2'))
self.end_row = int(config.get('bin', 'end_row_binning_2'))
self.calibration_file_name_image = config.get('calibration_file', 'cal_file_name_image_bining_2')
self.calibration_file_it_image = int(config.get('calibration_file', 'cal_file_it_image_bining_2'))
self.wavelength_file_name = config.get('wavelength_file_name', 'file_name')
self.image_dir = config.get('image_record_param', 'image_dir')
self.create_directory(self.image_dir)
self.default_image_name = config.get('image_record_param', 'default_image_name')
self.framerate = int(float(config.get('image_record_param', 'framerate')))
self.exposure_time = int(float(config.get('image_record_param', 'exposure_time')))
self.gain = int(float(config.get('image_record_param', 'gain')))
self.frame_number = int(float(config.get('image_record_param', 'frame_number')))
self.arcus_speed = int(float(config.get('image_record_param', 'arcus_speed')))
self.spectral_dir = config.get('spectral_record_param', 'spectral_dir')
self.create_directory(self.spectral_dir)
self.default_spectral_name = config.get('spectral_record_param', 'default_spectral_name')
self.spectral_number = int(float(config.get('spectral_record_param', 'spectral_number')))
self.framenumber_average = int(float(config.get('spectral_record_param', 'framenumber_average')))
self.exposure_time_spectral = int(float(config.get('spectral_record_param', 'exposure_time_spectral')))
# self.start_column = 12
# self.end_column = 1376
# self.start_row = 1
# self.end_row = 300
def image_record_param_changed(self, dictionary):
'''
:param dictionary: {'image_dir':值, 'image_record_param': 值}
:return:
'''
try:
# print('接收的参数个数:', len(dictionary.keys()))
config = configparser.ConfigParser()
config.read(self.corning_config_file)
for key in dictionary.keys():
# self.key = dictionary[key]
# config.set('image_record_param', key, dictionary[key])
if key == 'image_dir':
self.image_dir = dictionary[key]
config.set('image_record_param', key, dictionary[key])
if key == 'default_image_name':
self.default_image_name = dictionary[key]
config.set('image_record_param', key, dictionary[key])
if key == 'framerate':
self.framerate = dictionary[key]
config.set('image_record_param', key, str(dictionary[key]))
if key == 'exposure_time':
self.exposure_time = dictionary[key]
config.set('image_record_param', key, str(dictionary[key]))
if key == 'gain':
self.gain = dictionary[key]
config.set('image_record_param', key, str(dictionary[key]))
if key == 'frame_number':
self.frame_number = dictionary[key]
config.set('image_record_param', key, str(dictionary[key]))
if key == 'arcus_speed':
self.arcus_speed = dictionary[key]
config.set('image_record_param', key, str(dictionary[key]))
except:
traceback.print_exc()
with open(self.corning_config_file, 'w') as f:
config.write(f)
def spectral_record_param_changed(self, dictionary):
'''
:param dictionary: {'image_dir':值, 'image_record_param': 值}
:return:
'''
print(len(dictionary.keys()))
config = configparser.ConfigParser()
config.read(self.corning_config_file)
try:
for key in dictionary.keys():
if key == 'spectral_dir':
self.spectral_dir = dictionary[key]
config.set('spectral_record_param', key, dictionary[key])
if key == 'default_spectral_name':
self.default_spectral_name = dictionary[key]
config.set('spectral_record_param', key, dictionary[key])
if key == 'spectral_number':
self.spectral_number = dictionary[key]
config.set('spectral_record_param', key, str(dictionary[key]))
if key == 'framenumber_average':
self.framenumber_average = dictionary[key]
config.set('spectral_record_param', key, str(dictionary[key]))
if key == 'exposure_time_spectral':
self.exposure_time_spectral = dictionary[key]
config.set('spectral_record_param', key, str(dictionary[key]))
except:
traceback.print_exc()
with open(self.corning_config_file, 'w') as f:
config.write(f)
if __name__ == '__main__':
x = ConfigFile()

29
library/dir_manager.py Normal file
View File

@ -0,0 +1,29 @@
import os
from library.functions import get_path
class DirManager():
def __init__(self):
self.base_dir = get_path()
self.log_dir = self.base_dir + '//log'
self.create_directory(self.log_dir)
print(self.log_dir)
# 查看是否存在保存光谱和影像文件的目录,如果没有就创建
def create_directory(self, directory):
'''
:param directory: 需要创建的文件夹绝对路径不能将参数directory省略而在此函数内部使用self.log_dir
因为本类的继承类也需要使用此函数
:return:
'''
if not os.path.exists(directory):
print('创建文件夹:', directory)
os.makedirs(directory)
# else:
# print('文件夹存在:%s' % self.log_dir)
if __name__ == '__main__':
x = DirManager()

144
library/functions.py Normal file
View File

@ -0,0 +1,144 @@
# -*- coding:utf-8 -*-
'''
本模块是各种工具函数
'''
import sys, os
import numpy as np
def get_path():
'''
本函数说明https://pythonhosted.org/PyInstaller/runtime-information.html#using-sys-executable-and-sys-argv-0
:return: 返回运行程序的绝对路径
'''
frozen = 'not'
if getattr(sys, 'frozen', False):
# we are running in a bundle
bundle_dir = sys._MEIPASS
# print('we are running in a bundle(pyinstaller打包程序)!')
else:
# we are running in a normal Python environment
# bundle_dir = os.path.dirname(os.path.abspath(__file__)) # 此行代码返回的是本文件的路径,而不是本文件所导入的文件的路径
bundle_dir = os.getcwd()
# print('we are running in a normal Python environment(非pyinstaller打包程序)!')
return bundle_dir
def get_resource_path(relative_path):
'''
本函数说明https://www.zacoding.com/en/post/python-selenium-to-exe/
:param relative_path:
:return:
'''
try:
base_path = sys._MEIPASS
except Exception:
base_path = os.getcwd()
return os.path.join(base_path, relative_path)
def percentile_stretching(img, lowPercentile=0, highPercentile=100, minout=0, maxout=255):
'''
本程序用于拉伸影像
:param img:
:param lowPercentile:
:param highPercentile:
:param minout:
:param maxout:
:return:
'''
if len(img.shape) == 2:
low = np.percentile(img, lowPercentile)
up = np.percentile(img, highPercentile)
img_new = ((img - low) / (up - low)) * (maxout - minout) + minout
img_new[img_new < minout] = minout
img_new[img_new > maxout] = maxout
img_out = np.uint8(img_new)
return img_out
else: # 对于彩色照片,需要先单独对每个波段拉伸
img_new = np.empty(img.shape)
for i in range(img.shape[2]):
low = np.percentile(img[:, :, i], lowPercentile)
up = np.percentile(img[:, :, i], highPercentile)
img_new[:, :, i] = minout + ((img[:, :, i] - low) / (up - low)) * (maxout - minout)
img_new[:, :, i][img_new[:, :, i] < minout] = minout
img_new[:, :, i][img_new[:, :, i] > maxout] = maxout
img_out = np.uint8(img_new)
return img_out
def return_file_path(out, filepath, filename, model='image'):
'''
本程序功能在filepath中寻找所有包含filename所有文件filename1、filename2然后返回一个filename3
:param out: 永远传入一个空list[];用于存储所有递归调用
:param filepath:
:param filename:
:param model: 有两个模式image 和 spectral
:return:
'''
# 出现此处代码的原因是当次函数定义执行后函数定义就包含了out参数的引用
# 而out参数是可变参数每一次调用次函数都会改变out的值所有不能保证每次调用此函数时out==[]。
# 当第二次调用此方程时
# if out != []:
# if filename not in os.path.splitext(out[-1]):
# out = []
if model == 'image':
files = os.listdir(filepath)
for s in files:
abspath = os.path.join(filepath, s)
if os.path.isfile(abspath):
tmp = os.path.splitext(os.path.split(abspath)[1])[0]
if tmp not in out: # 防止重复记录
if filename in tmp:
out.append(tmp)
else:
pass
# print('没有进来')
elif os.path.isdir(abspath):
return_file_path(out, abspath, filename)
out.sort(key=lambda x: int(x.replace(filename, '')))
if out == []:
x = filename + str(0)
return os.path.join(filepath, x), 0
if out != []:
number = int(out[-1].replace(filename, '')) + 1
x = filename + str(number)
return os.path.join(filepath, x), number
elif model == 'spectral':
files = os.listdir(filepath)
for s in files:
abspath = os.path.join(filepath, s)
if os.path.isfile(abspath) and os.path.splitext(s)[1] == '.txt':
tmp = os.path.splitext(os.path.split(abspath)[1])[0]
if tmp not in out: # 防止重复记录
if filename in tmp:
out.append(tmp)
elif os.path.isdir(abspath):
return_file_path(out, abspath, filename)
out.sort(key=lambda x: int(x.replace(filename, '')))
if out == []:
x = filename + str(0) + '.txt'
return os.path.join(filepath, x), 0
if out != []:
number = int(out[-1].replace(filename, '')) + 1 # 现存最大文件号 + 1
x = filename + str(number) + '.txt'
return os.path.join(filepath, x), number
if __name__ == '__main__':
# print(get_path())
x = return_file_path([], r'D:\delete', 'sss', model='spectral')
print(x)
# y = return_file_path([], r'D:\delete', 'rr')
# print(y)

View File

@ -0,0 +1,40 @@
import sys, traceback
from osgeo import gdal
# 读写影像类
class ImageReaderWriter(object):
#读图像文件
@classmethod
def read_img(cls, filename, xoff=0, yoff=0, im_width=None, im_height=None):
try:
dataset = gdal.Open(filename) # 打开文件
if im_width == None:
im_width = dataset.RasterXSize # 栅格矩阵的列数
if im_height == None:
im_height = dataset.RasterYSize # 栅格矩阵的行数
num_bands = dataset.RasterCount # 栅格矩阵的波段数
im_geotrans = dataset.GetGeoTransform() # 仿射矩阵
im_proj = dataset.GetProjection() # 地图投影信息
im_data = dataset.ReadAsArray(xoff, yoff, im_width, im_height) # 将数据写成数组,对应栅格矩阵
del dataset
return im_proj, im_geotrans, im_data
except AttributeError:
print('gdal打开影像没有文件')
except Exception:
traceback.print_exc()
pass
#写文件以写成tif为例
@classmethod
def write_img(cls, dst_filename, data):
format = "ENVI"
driver = gdal.GetDriverByName(format)
RasterXSize = data.shape[2] # 遥感影像的sample列数
RasterYSize = data.shape[1] # 遥感影像的line行数
band = data.shape[0]
# driver.Create()函数中RasterXSize代表影像的sample列数RasterYSize代表影像的line行数
dst_ds = driver.Create(dst_filename, RasterXSize, RasterYSize, band, gdal.GDT_Float32)
for i in range(band):
dst_ds.GetRasterBand(i + 1).WriteArray(data[i, :, :]) # gdal的band从1开始所以dst_ds.GetRasterBand(i+1)
dst_ds = None

50
library/log.py Normal file
View File

@ -0,0 +1,50 @@
# 标准库
import traceback, os, logging
# 三方库
import configparser
# 自己写的库
from library.dir_manager import DirManager
class Log(DirManager):
def __init__(self):
super(Log, self).__init__()
self.log()
def log(self):
# 判断是否存在log文件如果不存在就创建
if not os.path.exists(self.log_dir + '//all_operate.log'):
with open(self.log_dir + '//all_operate.log', 'w') as f:
pass
if not os.path.exists(self.log_dir + '//error.log'):
with open(self.log_dir + '//error.log', 'w') as f:
pass
# 初始化log
root_logger = logging.getLogger('root')
root_logger.setLevel(level=logging.DEBUG) # logger级别设置为低级别代表这个logger可以处理很多级别的日志更灵活的处理放在logger中的各种handler中
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
all_operate_file_handler = logging.FileHandler(self.log_dir + '//all_operate.log') # 输出到文件
all_operate_file_handler.setLevel(logging.INFO)
all_operate_file_handler.setFormatter(formatter)
error_file_handler = logging.FileHandler(self.log_dir + '//error.log') # 输出到文件
error_file_handler.setLevel(logging.ERROR)
error_file_handler.setFormatter(formatter)
stream_handler = logging.StreamHandler() # 输出到控制台
stream_handler.setLevel(logging.INFO)
stream_handler.setFormatter(formatter)
root_logger.addHandler(all_operate_file_handler)
root_logger.addHandler(error_file_handler)
root_logger.addHandler(stream_handler)
if __name__ == '__main__':
x = Log()

View File

@ -0,0 +1,25 @@
[bin]
binning = 1
start_column_binning_1 = 12
end_column_binning_1 = 1376
start_row_binning_1 = 1
end_row_binning_1 = 301
start_column_binning_2 = 13
end_column_binning_2 = 695
start_row_binning_2 = 1
end_row_binning_2 = 150
[image_record_param]
image_dir = D:\py_program\corning410\library/image
default_image_name = test_image
framerate = 20
exposure_time = 500
gain = 0
frame_number = 20
[spectral_record_param]
spectral_dir = D:\py_program\corning410\library/spectral
default_spectral_name = test_spectral
spectral_number = 10
framenumber_average = 10

View File

@ -0,0 +1,161 @@
import matplotlib
matplotlib.use("Qt5Agg") # 声明使用QT5
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
import traceback
import time, sys
from functions import percentile_stretching
from PyQt5 import QtWidgets, QtCore, uic
import pyqtgraph as pg
from random import randint
class ArgsError(Exception):
pass
# 画图类,用于:画出采集到的光谱;调焦(影响模式调焦)
class MatplotlibSpectralViewer(FigureCanvas):
def __init__(self, xlabel=None, ylabel=None, width=5, height=4, dpi=100):
# 第一步创建一个创建Figure
self.fig = Figure(figsize=(width, height), dpi=dpi)
# 第二步在父类中激活Figure窗口
# this is the Canvas Widget that displays the `figure`
# it takes the `figure` instance as a parameter to __init__
super(MatplotlibSpectralViewer, self).__init__(self.fig) # 此句必不可少,否则不能显示图形
# 第三步创建一个子图用于绘制图形用111表示子图编号如matlab的subplot(1,1,1)
self.axes = self.fig.add_subplot(1, 1, 1)
self.axes.set_xlabel('Wavelength (nm)')
self.axes.set_ylabel('reflectance')
self.xlabel = xlabel
self.ylabel = ylabel
self._plotref = None # 这里代表曲线
self.axes.set_ylim(0, 1.2)
# 第四步:就是画图,【可以在此类中画,也可以在其它类中画】
def plot_wrap(self, *args):
if self.xlabel is not None:
self.axes.set_xlabel(self.xlabel)
if self.ylabel is not None:
self.axes.set_ylabel(self.ylabel)
try:
if self._plotref == None:
if len(args) == 0:
raise ArgsError('传入了0个参数本函数只能传入1/2个参数')
elif len(args) == 1:
self.axes.cla()
# self.axes.set_ylim(0, 1.2)
self._plotref = self.axes.plot(list(range(len(args[0]))), args[0])[0]
self.draw()
elif len(args) == 2:
self.axes.cla()
# self.axes.set_ylim(0, 1.2)
self._plotref = self.axes.plot(args[0], args[1])[0]
self.draw()
elif len(args) > 2:
raise ArgsError('传入了大于2个参数本函数只能传入1/2个参数')
elif self._plotref is not None:
if len(args) == 0:
raise ArgsError('传入了0个参数本函数只能传入1/2个参数')
elif len(args) == 1:
self._plotref.set_data(list(range(len(args[0]))), args[0])
# 更新显示区域
self.axes.set_xlim(min(list(range(len(args[0])))), max(list(range(len(args[0])))))
self.axes.set_ylim(min(args[0]), max(args[0]))
# self.axes.set_ylim(0, 1.2)
# 绘制图像
self.draw()
elif len(args) == 2:
self._plotref.set_data(args[0], args[1])
# 更新显示区域
self.axes.set_xlim(min(args[0]), max(args[0]))
self.axes.set_ylim(min(args[1]), max(args[1]))
# self.axes.set_ylim(0, 1.2)
# 绘制图像
self.draw()
elif len(args) > 2:
raise ArgsError('传入了大于2个参数本函数只能传入1/2个参数')
except Exception:
traceback.print_exc()
# 画图类,用于:画出采集到的图像;显示帧流(光谱模式对准光纤)
class MatplotlibImageViewer(FigureCanvas):
def __init__(self, width=5, height=4, dpi=100):
# 第一步创建一个创建Figure
self.fig = Figure(figsize=(width, height), dpi=dpi)
# 第二步在父类中激活Figure窗口
# this is the Canvas Widget that displays the `figure`
# it takes the `figure` instance as a parameter to __init__
super(MatplotlibImageViewer, self).__init__(self.fig) # 此句必不可少,否则不能显示图形
# 第三步创建一个子图用于绘制图形用111表示子图编号如matlab的subplot(1,1,1)
self.axes = self.fig.add_subplot(1, 1, 1)
self._plotref = None # 这里代表图像
# 第四步:就是画图,【可以在此类中画,也可以在其它类中画】
def setImage(self, image, lowPercentile=0, highPercentile=100):
self.axes.set_xticks([])
self.axes.set_yticks([])
if self._plotref == None:
self._plotref = self.axes.imshow(image)
self.draw()
elif self._plotref is not None:
self._plotref.set_data(percentile_stretching(image, lowPercentile, highPercentile))
self.draw()
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, *args, **kwargs):
super(MainWindow, self).__init__(*args, **kwargs)
# self.graphWidget = QtSpectralViewer()
self.graphWidget = MatplotlibSpectralViewer(xlabel='Wavelength (nm)', ylabel='reflectance')
self.setCentralWidget(self.graphWidget)
self.x = list(range(100)) # 100 time points
self.y = [randint(0, 100) for _ in range(100)] # 100 data points
# self.graphWidget.setBackground('w')
pen = pg.mkPen(color=(255, 0, 0))
self.graphWidget.plot_wrap(self.x, self.y)
self.timer = QtCore.QTimer()
self.timer.timeout.connect(self.update_plot_data)
self.timer.start(10)
def update_plot_data(self):
self.x = self.x[1:] # Remove the first y element.
self.x.append(self.x[-1] + 1) # Add a new value 1 higher than the last.
self.y = self.y[1:] # Remove the first
self.y.append(randint(0, 100)) # Add a new random value.
# self.data_line.setData(self.x, self.y) # Update the data.
self.graphWidget.plot_wrap(self.x, self.y)
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())

53
library/message_box.py Normal file
View File

@ -0,0 +1,53 @@
from PyQt5.QtWidgets import QApplication, QDialog
from PyQt5.QtCore import Qt
import sys
from library.message_box_ui import *
class MessageBox(QDialog, Ui_message_box_ui):
def __init__(self, txt, parent=None):
'''
The super().__init__() method invokes the base class constructor from the MyForm class,
that is, the constructor of the QDialog class is invoked from MyForm class to indicate that
QDialog is displayed through this class iss a top-level window.
'''
super(MessageBox, self).__init__(parent)
self.setupUi(self)
# self.setWindowState(Qt.WindowMaximized) # 初始化时就最大化窗口
self.setWindowModality(Qt.ApplicationModal) # 阻塞此窗口只能在关闭此窗口之后才能操作后面的窗口但是不会阻塞调用此窗口的进程的代码此行代码必须放在show()函数之前
# self.setWindowModality(Qt.WindowModal)
# 无边框
# self.setWindowFlags(Qt.FramelessWindowHint)
self.txt = txt
self.info()
self.confirm_bt.clicked.connect(self.shutdown)
# 禁止调整大小
# self.setFixedSize(self.width(), self.height())
def info(self):
self.info_label.setText(self.txt)
# self.exec() # 阻塞调用此窗口后的进程的代码,只有此窗口返回后才能执行此窗口外的代码
# self.show() # 只是显示,不会阻塞任何代码
def shutdown(self):
self.close()
if __name__ == '__main__':
app = QApplication(sys.argv)
x = MessageBox('请先曝光和采集暗电流!')
# x.show()
sys.exit(app.exec_())

90
library/message_box_ui.py Normal file
View File

@ -0,0 +1,90 @@
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'message_box_ui.ui'
#
# Created by: PyQt5 UI code generator 5.13.0
#
# WARNING! All changes made in this file will be lost!
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_message_box_ui(object):
def setupUi(self, message_box_ui):
message_box_ui.setObjectName("message_box_ui")
message_box_ui.resize(487, 385)
self.gridLayout = QtWidgets.QGridLayout(message_box_ui)
self.gridLayout.setObjectName("gridLayout")
self.info_label = QtWidgets.QLabel(message_box_ui)
self.info_label.setStyleSheet("QLabel\n"
"{\n"
" /*字体为微软雅黑*/\n"
" font-family:Microsoft Yahei;\n"
" /*字体大小为20点*/\n"
" font-size:30pt;\n"
" /*字体颜色为白色*/\n"
" /*color:white;*/\n"
" /*背景颜色*/\n"
" /*background-color:rgb(14 , 150 , 254);*/\n"
" /*边框圆角半径为8像素*/\n"
" /*border-radius:8px;*/\n"
"}")
self.info_label.setAlignment(QtCore.Qt.AlignCenter)
self.info_label.setObjectName("info_label")
self.gridLayout.addWidget(self.info_label, 0, 0, 1, 1)
self.confirm_bt = QtWidgets.QPushButton(message_box_ui)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Preferred)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.confirm_bt.sizePolicy().hasHeightForWidth())
self.confirm_bt.setSizePolicy(sizePolicy)
self.confirm_bt.setMinimumSize(QtCore.QSize(0, 130))
self.confirm_bt.setAcceptDrops(False)
self.confirm_bt.setStyleSheet("/*按钮普通态*/\n"
"QPushButton\n"
"{\n"
" /*字体为微软雅黑*/\n"
" font-family:Microsoft Yahei;\n"
" /*字体大小为20点*/\n"
" font-size:25pt;\n"
" /*字体颜色为白色*/ \n"
" /*color:white;*/\n"
" /*背景颜色*/ \n"
" background-color:rgb(225 , 225 , 225);\n"
" /*边框圆角半径为8像素*/ \n"
" border-radius:20px;\n"
"}\n"
"\n"
"/*按钮停留态*/\n"
"QPushButton:hover\n"
"{\n"
" /*背景颜色*/ \n"
" background-color:rgb(44 , 137 , 255);\n"
" /*边框圆角半径为8像素*/\n"
" /*border-radius:20px;*/\n"
"}\n"
"\n"
"/*按钮按下态*/\n"
"QPushButton:pressed\n"
"{\n"
" /*背景颜色*/ \n"
" background-color:rgb(255 , 0 , 0);\n"
"\n"
" /*左内边距为3像素让按下时字向右移动3像素*/ \n"
" padding-left:3px;\n"
"\n"
" /*上内边距为3像素让按下时字向下移动3像素*/ \n"
" padding-top:3px;\n"
"}")
self.confirm_bt.setObjectName("confirm_bt")
self.gridLayout.addWidget(self.confirm_bt, 1, 0, 1, 1)
self.retranslateUi(message_box_ui)
QtCore.QMetaObject.connectSlotsByName(message_box_ui)
def retranslateUi(self, message_box_ui):
_translate = QtCore.QCoreApplication.translate
message_box_ui.setWindowTitle(_translate("message_box_ui", "提示"))
self.info_label.setText(_translate("message_box_ui", "提示信息"))
self.confirm_bt.setText(_translate("message_box_ui", "确定"))

106
library/message_box_ui.ui Normal file
View File

@ -0,0 +1,106 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>message_box_ui</class>
<widget class="QDialog" name="message_box_ui">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>487</width>
<height>385</height>
</rect>
</property>
<property name="windowTitle">
<string>提示</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="info_label">
<property name="styleSheet">
<string notr="true">QLabel
{
/*字体为微软雅黑*/
font-family:Microsoft Yahei;
/*字体大小为20点*/
font-size:30pt;
/*字体颜色为白色*/
/*color:white;*/
/*背景颜色*/
/*background-color:rgb(14 , 150 , 254);*/
/*边框圆角半径为8像素*/
/*border-radius:8px;*/
}</string>
</property>
<property name="text">
<string>提示信息</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QPushButton" name="confirm_bt">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>130</height>
</size>
</property>
<property name="acceptDrops">
<bool>false</bool>
</property>
<property name="styleSheet">
<string notr="true">/*按钮普通态*/
QPushButton
{
/*字体为微软雅黑*/
font-family:Microsoft Yahei;
/*字体大小为20点*/
font-size:25pt;
/*字体颜色为白色*/
/*color:white;*/
/*背景颜色*/
background-color:rgb(225 , 225 , 225);
/*边框圆角半径为8像素*/
border-radius:20px;
}
/*按钮停留态*/
QPushButton:hover
{
/*背景颜色*/
background-color:rgb(44 , 137 , 255);
/*边框圆角半径为8像素*/
/*border-radius:20px;*/
}
/*按钮按下态*/
QPushButton:pressed
{
/*背景颜色*/
background-color:rgb(255 , 0 , 0);
/*左内边距为3像素让按下时字向右移动3像素*/
padding-left:3px;
/*上内边距为3像素让按下时字向下移动3像素*/
padding-top:3px;
}</string>
</property>
<property name="text">
<string>确定</string>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

81
library/multithread.py Normal file
View File

@ -0,0 +1,81 @@
import sys, traceback
from PyQt5.QtCore import QRunnable, QObject, pyqtSignal, pyqtSlot
class WorkerSignals(QObject):
'''
Defines the signals available from a running worker thread.
Supported signals are:
finished
No data
error
`tuple` (exctype, value, traceback.format_exc() )
result
`object` data returned from processing, anything
progress
`int` indicating % progress
# 信号必须定义为类属性不能放在__init__方法里
'''
finished = pyqtSignal()
error = pyqtSignal(tuple)
result = pyqtSignal(object)
progress = pyqtSignal(int) # 可以用作进度条
serial = pyqtSignal(object) # 2record_system_v26的此信号移动到类SerialPort中了
image_signal = pyqtSignal(dict) # 只用在2record_system_v25中
spectral_signal = pyqtSignal(dict) # 只用在2record_system_v25中
openinfo = pyqtSignal(int) # 只用在2record_system_v25中
plotsignal = pyqtSignal() # 2record_system_v26的此信号移动到类ImageWindowPhone中了
# https://www.learnpyqt.com/courses/concurrent-execution/multithreading-pyqt-applications-qthreadpool/
# 用于qt多线程运行long-time task
class Worker(QRunnable):
'''
Worker thread
Inherits from QRunnable to handler worker thread setup, signals and wrap-up.
:param callback: The function callback to run on this worker thread. Supplied args and
kwargs will be passed through to the runner.
:type callback: function
:param args: Arguments to pass to the callback function
:param kwargs: Keywords to pass to the callback function
'''
def __init__(self, fn, *args, **kwargs):
super(Worker, self).__init__()
# Store constructor arguments (re-used for processing)
self.fn = fn
self.args = args
self.kwargs = kwargs
self.signals = WorkerSignals()
# Add the callback to our kwargs
# self.kwargs['progress_callback'] = self.signals.progress
@pyqtSlot()
def run(self):
'''
Initialise the runner function with passed args, kwargs.
'''
try: # 如果有错,就捕捉错误
result = self.fn(*self.args, **self.kwargs)
except Exception: # 根据错误进行处理
traceback.print_exc()
exctype, value = sys.exc_info()[:2]
self.signals.error.emit((exctype, value, traceback.format_exc()))
else: # 如果没有错误执行下面代码
self.signals.finished.emit() # Done
self.signals.result.emit(result) # Return the result of the processing
finally: # 不管有错无错,都要执行下面代码
pass