class CameraMainWindow(QMainWindow): def __init__(self): super().__init__() uic.loadUi('MainWin.ui', self) self.setWindowTitle('CamPaint') self.setWindowIcon(QIcon('main_icon.ico')) self.setCentralWidget(self.tabWidget) # Загружаем камеру, холст, sql файл и задаем цвета кнопок self.load_cam() self.load_painter() self.load_sql() self.load_colors() def load_cam(self): self.cam_page.setLayout(self.cam_page_lay) self.error_cam.hide() self.camera = QCameraInfo.defaultCamera() # Проверяем, что камера сущетсвует # Если нет, то переключаемся на вторую вкладку if self.camera.isNull(): dialog = QErrorMessage() dialog.setWindowTitle('Warning') dialog.showMessage( 'Not enough cameras, the app will only be available in drawing mode' ) dialog.exec() self.error_cam.show() self.cam_page.setEnabled(False) self.tabWidget.setCurrentIndex(1) # Если да, то на первую else: self.tabWidget.setCurrentIndex(0) self.camera = QCamera(self.camera) self.view_cam = QCameraViewfinder(self) self.view_cam.setMediaObject(self.camera) self.view_cam.setAutoFillBackground(True) self.camera.setViewfinder(self.view_cam) self.box_lay = QVBoxLayout(self) self.box_lay.addWidget(self.view_cam) self.scrolling.setLayout(self.box_lay) # Запускаем камеру self.camera.start() # Подвязываем кнопку к слоту со снимком self.bt_cam.clicked.connect(self.make_ph) # Можно зумить фотографию self.zoom.valueChanged.connect(self.zoom_pict) def make_ph(self): self.camera.setCaptureMode(QCamera.CaptureStillImage) self.capt = QCameraImageCapture(self.camera) # Останавливаем съемку self.camera.searchAndLock() # Вызываем диалог и иохранением файла dial = QFileDialog.getSaveFileName( self, 'Save file', '', 'Картинка (*.jpg);;Картинка (*.png);;Все файлы (*)')[0] if dial: self.capt.capture(dial) self.camera.unlock() def zoom_pict(self, value): # Вычисляем зум камеры по функции zoom=1.0 + value * 3 / 99 # 1.0 - обязательный параметр QCameraFocus.zoomTo(self.camera.focus(), 1.0 + value * 3 / 99, 1.0) def load_painter(self): # Загружаем холст self.paint_page.setLayout(self.paint_page_lay) # Текущий цвет - черный, ширина кисти - 10 self.now_col = QColor(0, 0, 0) self.now_width = 10 self.point_width.setValue(10) # Подвязываем кнопку с изменением ширины кисти к соответсвующему слоту self.point_width.valueChanged.connect(self.change_width) # Создаем холст как экземпляр класса Canvas из доп.модуля Canvas self.canvas = Canvas.Canvas(self.main_paint_widg) self.canvas.move(1, 1) self.canvas.resize(self.main_paint_widg.width() - 1, self.main_paint_widg.height() - 1) print(self.main_paint_widg.size(), self.canvas.size(), self.border_lab.size()) # Устанавливаем границы рамки self.border_lab.setStyleSheet( 'border-style: solid; border-width: 2px; border-color: black;') self.canvas.setStyleSheet('background-color: white;') # Устанавливаем сильный фокус для перехвата всех событий # клавиатуры и мыши self.setFocusPolicy(Qt.StrongFocus) # Подвязываем действия из меню к слотам self.actionSave.triggered.connect(self.save_file) self.actionSave_as.triggered.connect(self.save_as_file) self.actionOpen.triggered.connect(self.open_file) self.actionReference.triggered.connect(self.open_reference) # и кнопку очистки холста, а также задания цвета кисти self.bt_clear.clicked.connect(self.clear_canvas) self.bt_set_color.clicked.connect(self.set_color_with_bt) # Имя файла изначально не задано, файл не сохранен self.file_name = '' self.saved = False self.resizeEvent(QResizeEvent(self.size(), self.size())) def change_width(self, value): self.now_width = value def keyPressEvent(self, event): # Обрабатываем события клавитатуры if int(event.modifiers()) == Qt.CTRL and event.key() == Qt.Key_Z: # Функция 'назад', удаляем все объекты, которые нарисовали if self.canvas.obj: del self.canvas.obj[-1] self.canvas.update() elif int(event.modifiers()) == Qt.CTRL and event.key() == Qt.Key_S: # Функция 'сохранить', сохраняем файл, если есть изменения if self.canvas.obj: self.save_file() elif int(event.modifiers()) == Qt.CTRL and event.key() == Qt.Key_O: # Функция 'открыть', открываем файл self.open_file() elif int(event.modifiers()) == Qt.CTRL and event.key() == Qt.Key_H: # Функция 'справка', открываем справку self.open_reference() def resizeEvent(self, event): # При изменении размеров окна, устанавливаем соответствующие размеры холста и рамки self.canvas.resize(self.main_paint_widg.width() - 1, self.main_paint_widg.height() - 1) self.border_lab.resize(self.main_paint_widg.width(), self.main_paint_widg.height()) def save_as_file(self): # Сохранение файла как dial = \ QFileDialog.getSaveFileName(self, 'Save file as', '', 'Картинка (*.jpg);;Картинка (*.png);;Все файлы (*)')[ 0] if dial: # Захватываем изображжение с холста и сохраняем pixmap = QPixmap(self.canvas.grab()) pixmap.save(dial) # Сохраняем имя файла в переменной self.file_name, чтобы использовать в функции save_file # Очищаем нарисованные объекты, так как уже их сохранили self.file_name = dial self.saved = True self.canvas.obj = [] def save_file(self): # Если имя файла выбрано, просто сохраняем if self.file_name: pixmap = QPixmap(self.canvas.grab()) pixmap.save(self.file_name) self.saved = True self.canvas.obj = [] # В ином случае, сохраняем как else: self.save_as_file() def open_file(self): # Открываем новый файл dial = QFileDialog.getOpenFileName( self, 'Open file', '', 'Картинка (*.jpg);;Картинка (*.png);;Все файлы (*)')[0] if dial: # Если старый файл не сохранен, предлагаем сохранить его if self.canvas.obj and not self.saved: dial2 = Dialogs.Message() res = dial2.exec() if res == dial2.Save: self.save_file() if res == dial2.Cancel: pass # Сохраняем новое имя файла, вызываем функцию open_file в экземпляре холста self.file_name = dial self.canvas.obj = [] self.canvas.open_file() def open_reference(self): dial = Dialogs.Reference() dial.exec() def clear_canvas(self): # Очищаем нарисованные объекты self.canvas.obj.clear() self.canvas.update() def set_color(self, color): # Устанавливаем текущий цвет self.now_col = color red, green, blue = color.red(), color.green(), color.blue() # Подключаемся к базе данных в папке проекта # и добавляем его к любимым цветам пользователя con = sqlite3.connect('own_colors_db.db') cur = con.cursor() colors = cur.execute( f'''SELECT * from colors WHERE red={red} and green={green} and blue={blue}''' ).fetchall() if colors: id = colors[0][0] cur.execute( f'''UPDATE colors SET counts=counts + 1 WHERE id={id}''') else: last_id = cur.execute( f'''SELECT id from colors''').fetchall()[-1][0] cur.execute( f'''INSERT INTO colors VALUES ({last_id + 1}, {red}, {green}, {blue}, 1)''' ) con.commit() con.close() def set_color_with_bt(self): # Слот для кнопки выбора цвета color = QColorDialog.getColor() self.set_color(color) def closeEvent(self, event): # Закрываем файл, обнуляя значение зума self.zoom.setValue(1) # И предлагаем сохранить файл, если он не сохранен if self.canvas.obj and not self.saved: dial = Dialogs.Message() res = dial.exec() if res == dial.Save: self.save_file() if res == dial.Cancel: event.ignore() def load_sql(self): # При отсутствии цветов в базе данных(в первом открытии приложения) # добавляем в базу данных новый цвет - черный con = sqlite3.connect('own_colors_db.db') cur = con.cursor() len_sql = len(cur.execute(f'''SELECT * from colors''').fetchall()) if len_sql == 0: cur.execute('''INSERT INTO colors VALUES (1, 0, 0, 0, 1)''') con.commit() con.close() def load_colors(self): # Загружаем цвета в кнопки любимых цветов пользователя colors = [] con = sqlite3.connect('own_colors_db.db') cur = con.cursor() ex_colors = sorted(cur.execute( '''SELECT red, green, blue, counts from colors''').fetchall(), key=lambda i: i[3])[:21] ex_colors = [(i[0], i[1], i[2]) for i in ex_colors] colors.extend(ex_colors) # Если цветов недостаточно, заполняем кнопки случайными цветами # вдруг какой-нибудь из них ползователю понравится if len(colors) < 20: for i in range(20 - len(colors)): new_color = (randrange(256), randrange(256), randrange(256)) while new_color in colors: new_color = (randrange(256), randrange(256), randrange(256)) colors.append(new_color) # Сохраняем цвета кнопок в словарь, где ключ - кнопка, значение - цвет # А также подключаем кнопки к слоту и изменением цвета self.bt_colors_dict = {} for i in range(4): for j in range(5): exec( f'self.bt{i}{j}.setStyleSheet("background:rgb({colors[0][0]}, {colors[0][1]}, {colors[0][2]});")' ) color = QColor(colors[0][0], colors[0][1], colors[0][2]) exec(f'self.bt_colors_dict[self.bt{i}{j}] = color') exec(f'self.bt{i}{j}.clicked.connect(self.set_color_with_bts)') del colors[0] def set_color_with_bts(self): # Слот для установки цвета кисти self.set_color(self.bt_colors_dict[self.sender()])
class QmyMainWindow(QMainWindow): def __init__(self, parent=None): super().__init__(parent) #调用父类构造函数,创建窗体 self.ui = Ui_MainWindow() #创建UI对象 self.ui.setupUi(self) #构造UI界面 self.__LabCameraState = QLabel("摄像头state:") self.__LabCameraState.setMinimumWidth(150) self.ui.statusBar.addWidget(self.__LabCameraState) self.__LabImageID = QLabel("图片文件ID:") self.__LabImageID.setMinimumWidth(100) self.ui.statusBar.addWidget(self.__LabImageID) self.__LabImageFile = QLabel("") #保存的图片文件名 ## self.ui.statusBar.addWidget(self.__LabImageFile) self.ui.statusBar.addPermanentWidget(self.__LabImageFile) self.camera = None #QCamera对象 cameras = QCameraInfo.availableCameras() #list[QCameraInfo] if len(cameras) > 0: self.__iniCamera() #初始化摄像头 self.__iniImageCapture() #初始化静态画图 self.camera.start() ## ==============自定义功能函数======================== def __iniCamera(self): ##创建 QCamera对象 camInfo = QCameraInfo.defaultCamera() #获取缺省摄像头,QCameraInfo self.ui.comboCamera.addItem(camInfo.description()) #摄像头描述 self.ui.comboCamera.setCurrentIndex(0) self.camera = QCamera(camInfo) #创建摄像头对象 self.camera.setViewfinder(self.ui.viewFinder) #设置取景框预览 ## camera.setCaptureMode(QCamera.CaptureViewfinder) #预览 self.camera.setCaptureMode(QCamera.CaptureStillImage) #设置为抓图 ## camera.setCaptureMode(QCamera.CaptureVideo) mode = QCamera.CaptureStillImage supported = self.camera.isCaptureModeSupported(mode) self.ui.checkStillImage.setChecked(supported) #支持拍照 supported = self.camera.isCaptureModeSupported(QCamera.CaptureVideo) self.ui.checkVideo.setChecked(supported) #支持视频录制 supported = self.camera.exposure().isAvailable() self.ui.checkExposure.setChecked(supported) #支持曝光补偿 supported = self.camera.focus().isAvailable() self.ui.checkFocus.setChecked(supported) #支持变焦 self.camera.stateChanged.connect(self.do_cameraStateChanged) def __iniImageCapture(self): ##创建 QCameraImageCapture对象 self.capturer = QCameraImageCapture(self.camera) settings = QImageEncoderSettings() #拍照设置 settings.setCodec("image/jpeg") #设置抓图图形编码 settings.setResolution(640, 480) #分辨率 settings.setQuality(QMultimedia.HighQuality) #图片质量 self.capturer.setEncodingSettings(settings) self.capturer.setBufferFormat(QVideoFrame.Format_Jpeg) #缓冲区格式 if self.ui.chkBoxSaveToFile.isChecked(): dest = QCameraImageCapture.CaptureToFile #保存到文件 else: dest = QCameraImageCapture.CaptureToBuffer #保存到缓冲区 self.capturer.setCaptureDestination(dest) #保存目标 self.capturer.readyForCaptureChanged.connect(self.do_imageReady) self.capturer.imageCaptured.connect(self.do_imageCaptured) self.capturer.imageSaved.connect(self.do_imageSaved) ## ==============event处理函数========================== ## ==========由connectSlotsByName()自动连接的槽函数============ @pyqtSlot(bool) ##设置保存方式 def on_chkBoxSaveToFile_clicked(self, checked): if checked: dest = QCameraImageCapture.CaptureToFile #保存到文件 else: dest = QCameraImageCapture.CaptureToBuffer #保存到缓冲区 self.capturer.setCaptureDestination(dest) #保存目标 @pyqtSlot() ##拍照 def on_actCapture_triggered(self): QSound.play("shutter.wav") #播放快门音效 self.camera.searchAndLock() #快门半按下时锁定摄像头参数 self.capturer.capture() #拍照 self.camera.unlock() #快门按钮释放时解除锁定 @pyqtSlot() ##打开摄像头 def on_actStartCamera_triggered(self): self.camera.start() @pyqtSlot() ##关闭摄像头 def on_actStopCamera_triggered(self): self.camera.stop() ## =============自定义槽函数=============================== def do_cameraStateChanged(self, state): ##摄像头状态变化 if (state == QCamera.UnloadedState): self.__LabCameraState.setText("摄像头state: UnloadedState") elif (state == QCamera.LoadedState): self.__LabCameraState.setText("摄像头state: LoadedState") elif (state == QCamera.ActiveState): self.__LabCameraState.setText("摄像头state: ActiveState") self.ui.actStartCamera.setEnabled(state != QCamera.ActiveState) self.ui.actStopCamera.setEnabled(state == QCamera.ActiveState) def do_imageReady(self, ready): ##是否可以拍照了 self.ui.actCapture.setEnabled(ready) def do_imageCaptured(self, imageID, preview): ##图片被抓取到内存 #preview是 QImage H = self.ui.LabImage.height() W = self.ui.LabImage.width() scaledImage = preview.scaled(W, H, Qt.KeepAspectRatio, Qt.SmoothTransformation) self.ui.LabImage.setPixmap(QPixmap.fromImage(scaledImage)) self.__LabImageID.setText("图片文件ID:%d" % imageID) self.__LabImageFile.setText("图片保存为: ") def do_imageSaved(self, imageID, fileName): ##图片被保存 self.__LabImageID.setText("图片文件ID:%d" % imageID) self.__LabImageFile.setText("图片保存为: " + fileName)
def main(): app = QApplication( sys.argv ) # must be called in order to be able to use all the stuff below(!) print("The application is executed on: %s" % app.platformName()) l_cameras = QCameraInfo.availableCameras() if len(l_cameras) == 0: print("ERROR: no cameras found") sys.exit(-1) else: print("INFO: found %i camera(s)" % len(l_cameras)) print() for i_idx, oc_caminfo in enumerate(l_cameras): # QCameraInfo - derived properties print("Camera #%i:" % i_idx) print("\t deviceName: %s" % oc_caminfo.deviceName()) print("\t description: %s" % oc_caminfo.description()) print("\t isNull: %s" % oc_caminfo.isNull()) print("\t orientation: %s" % oc_caminfo.orientation()) print("\t position: %s" % oc_caminfo.position()) # QCamera - derived properties oc_camera = QCamera(i_idx) camera_sync_load_and_start(oc_camera) oc_camera_exposure = oc_camera.exposure() print("\t captureMode: %s" % captureMode2str(oc_camera.captureMode())) print("\t exposure:") print("\t\t isAvailabe: %s" % oc_camera_exposure.isAvailable()) if oc_camera_exposure.isAvailable(): print("\t\t aperture: %s" % oc_camera_exposure.aperture()) # TODO test this, add more entries oc_camera_focus = oc_camera.focus() print("\t focus:") print("\t\t isAvailabe: %s" % oc_camera_focus.isAvailable()) if oc_camera_focus.isAvailable(): print("\t\t aperture: %f" % oc_camera_focus.digitalZoom()) # TODO test this, add more entries oc_cam_img_proc = oc_camera.imageProcessing() print("\t imageProcessing:") print("\t\t isAvailabe: %s" % oc_cam_img_proc.isAvailable()) if oc_cam_img_proc.isAvailable(): print("\t\t brightness: %f" % oc_cam_img_proc.brightness()) print("\t\t contrast: %f" % oc_cam_img_proc.contrast()) print("\t\t denoisingLevel: %f" % oc_cam_img_proc.denoisingLevel()) print("\t\t manualWhiteBalance: %f" % oc_cam_img_proc.manualWhiteBalance()) print("\t\t saturation: %f" % oc_cam_img_proc.saturation()) print("\t\t sharpeningLevel: %f" % oc_cam_img_proc.sharpeningLevel()) print("\t isVideoCaptureSupported: %s" % oc_camera.isCaptureModeSupported(QCamera.CaptureVideo)) print("\t lockStatus: %s" % lockStatus2str(oc_camera.lockStatus())) print("\t requestedLocks: %s" % lockType2str(oc_camera.requestedLocks())) print("\t state: %s" % state2str(oc_camera.state())) print("\t status: %s" % status2str(oc_camera.status())) print("\t supportedLocks: %s" % lockType2str(oc_camera.supportedLocks())) print( "\t supportedViewfinderFrameRateRanges: %s" % frameRateRange2str(oc_camera.supportedViewfinderFrameRateRanges())) print("\t supportedViewfinderPixelFormats: %s" % repr(oc_camera.supportedViewfinderPixelFormats())) print("\t supportedViewfinderResolutions: \n\t\t%s" % frameResolution2str(oc_camera.supportedViewfinderResolutions())) print("\t len(supportedViewfinderSettings): %s" % len(oc_camera.supportedViewfinderSettings())) # QCameraViewfinderSettings - derived properties oc_vf_settings = oc_camera.viewfinderSettings() if oc_vf_settings.isNull(): print("\t viewfinderSettings: not supported") camera_sync_stop_and_unload(oc_camera) print() continue print("\t maximumFrameRate: %f" % oc_vf_settings.maximumFrameRate()) print("\t minimumFrameRate: %f" % oc_vf_settings.minimumFrameRate()) print("\t resolution: %s" % frameResolution2str([oc_vf_settings.resolution()])) # TODO the rest of methods... camera_sync_stop_and_unload(oc_camera) print()