01图像采集第一版

参考消息:

  • 图片编辑(画板画线):

手写板的四步实现

QPixmap绘图的两种实现方式
图片画直线的demo(找到的灵感)

# 2020/8/31
# 关键:将mousemove中的命令移动到mouserelease中
import sys
from PyQt5.QtWidgets import (QApplication, QWidget)
from PyQt5.QtGui import (QPainter, QPen)
from PyQt5.QtCore import Qt

class Example(QWidget):
    def __init__(self):
        super(Example, self).__init__()
        #resize设置宽高,move设置位置
        self.resize(400, 300)
        self.move(100, 100)
        self.setWindowTitle("简单的画板4.0")
        #setMouseTracking设置为False,否则不按下鼠标时也会跟踪鼠标事件
        self.setMouseTracking(False)
        '''
            要想将按住鼠标后移动的轨迹保留在窗体上
            需要一个列表来保存所有移动过的点
        '''
        self.pos_xy = []

    def paintEvent(self, event):
        painter = QPainter()
        painter.begin(self)
        pen = QPen(Qt.black, 2, Qt.SolidLine)
        painter.setPen(pen)

        '''
            首先判断pos_xy列表中是不是至少有两个点了
            然后将pos_xy中第一个点赋值给point_start
            利用中间变量pos_tmp遍历整个pos_xy列表
                point_end = pos_tmp

                判断point_end是否是断点,如果是
                    point_start赋值为断点
                    continue
                判断point_start是否是断点,如果是
                    point_start赋值为point_end
                    continue

                画point_start到point_end之间的线
                point_start = point_end
            这样,不断地将相邻两个点之间画线,就能留下鼠标移动轨迹了
        '''
        if len(self.pos_xy) > 1:
            point_start = self.pos_xy[0]
            for pos_tmp in self.pos_xy:
                point_end = pos_tmp

                if point_end == (-1, -1):
                    point_start = (-1, -1)
                    continue
                if point_start == (-1, -1):
                    point_start = point_end
                    continue

                painter.drawLine(point_start[0], point_start[1], point_end[0], point_end[1])
                point_start = point_end
        painter.end()

    def mousePressEvent(self, event):
        '''
            按住鼠标移动事件:将当前点添加到pos_xy列表中
            调用update()函数在这里相当于调用paintEvent()函数
            每次update()时,之前调用的paintEvent()留下的痕迹都会清空
        '''
        #中间变量pos_tmp提取当前点
        pos_tmp = (event.pos().x(), event.pos().y())
        #pos_tmp添加到self.pos_xy中
        self.pos_xy.append(pos_tmp)
        self.update()

    def mouseReleaseEvent(self, event):
        '''
            重写鼠标按住后松开的事件
            在每次松开后向pos_xy列表中添加一个断点(-1, -1)
            然后在绘画时判断一下是不是断点就行了
            是断点的话就跳过去,不与之前的连续
        '''
        pos_tmp = (event.pos().x(), event.pos().y())
        # pos_tmp添加到self.pos_xy中
        self.pos_xy.append(pos_tmp)
        pos_test = (-1, -1)
        self.pos_xy.append(pos_test)
        self.update()

if __name__ == "__main__":
    app = QApplication(sys.argv)
    pyqt_learn = Example()
    pyqt_learn.show()
    app.exec_()
# 8/31 改进中:图片编辑直线  行数:##  ;查找:像素裁剪
from PyQt5 import QtGui
from sys import argv,exit
import time,cv2
from PyQt5.QtPrintSupport import QPageSetupDialog,QPrintDialog, QPrinter
from PyQt5.QtWidgets import  QVBoxLayout, QPushButton, QSplitter,\
    QComboBox, QLabel, QSpinBox, QFileDialog,QGridLayout
from PyQt5.QtWidgets import *
from PyQt5 import QtCore,QtWidgets
from PyQt5.QtGui import *
from PyQt5.Qt import QPixmap, QPainter, QPoint, QPen,QColor, QSize, QIcon
from PyQt5.QtCore import Qt

class Window(QMainWindow):
    def __init__(self):
        super().__init__()

        self.timer_camera = QtCore.QTimer()
        self.cap = cv2.VideoCapture()
        self.CAM_NUM = 0

        self.printer = QPrinter()

        self.setWindowTitle('图像采集')
        # self.width = 700                                                  # 页面大小
        # self.height = in                                               t(0.618 * self.width)
        # self.resize(self.width, self.height)
        self.setFixedSize(960, 700)
        self.picedit = MainWidget()

        self.button_1 = QtWidgets.QPushButton('样品扫描', self)
        self.button_2 = QtWidgets.QPushButton('关闭摄像头', self)
        self.button_7 = QtWidgets.QPushButton('打开摄像头',self)
        self.button_3 = QtWidgets.QPushButton('拍照', self)
        self.button_4 = QtWidgets.QPushButton('图片编辑', self)
        self.button_5 = QtWidgets.QPushButton('打印编码', self)
        self.button_6 = QtWidgets.QPushButton('打印设置', self)


        self.label_1 = QtWidgets.QLabel('样品编码', self)
        self.label_2 = QtWidgets.QLabel('二级编码', self)
        self.label_3 = QtWidgets.QLabel('psn', self)
        self.edit_n2 = QtWidgets.QTextEdit('null_2', self)          # #
        self.label_cv2 = QtWidgets.QLabel('拍照主页面',self)

        self.label_cv2.setStyleSheet("QLabel{color:rgb(225,22,173,255);background-color: white;font-size:50px;font-weight:normal;font-family:Arial;}")
        self.label_display = QtWidgets.QLabel('照片显示', self)

        self.initUI()
        self.slot_init()



    def initUI(self):
        # setting up layout of main window

        upper_widget = self.create_upper_widget()
        lower_widget = self.create_lower_widget()

        main_layout = QtWidgets.QVBoxLayout()
        main_layout.addWidget(upper_widget)                         # 整体layout包含上下两个widget
        main_layout.addWidget(lower_widget)
        main_layout.setStretch(0, 1)
        main_layout.setStretch(1, 10)                                # layout 比例调节
        main_widget = QtWidgets.QWidget()
        main_widget.setLayout(main_layout)                          # 将layout添加到widget
        self.setCentralWidget(main_widget)                          # widget 设为中心


    def create_upper_widget(self):                                  # 上部分layout添加到widget
        upper_layout = QtWidgets.QHBoxLayout()
        upper_layout.addWidget(self.button_1)
        upper_layout.addWidget(self.button_2)
        upper_layout.addWidget(self.button_7)
        upper_layout.addWidget(self.button_3)
        upper_layout.addWidget(self.button_4)
        upper_layout.addWidget(self.button_5)
        upper_layout.addWidget(self.button_6)

        upper_widget = QtWidgets.QWidget()
        upper_widget.setLayout(upper_layout)
        return upper_widget


    def create_lower_widget(self):
        lower_layout = QtWidgets.QGridLayout()
        lower_layout.addWidget(self.label_1,0,0,1,1)
        lower_layout.addWidget(self.label_3,0,1,1,6)
        lower_layout.addWidget(self.label_2,0,7,1,2)
        lower_layout.addWidget(self.label_cv2,1,1,6,6)
        lower_layout.addWidget(self.edit_n2,1,7,7,2)
        lower_layout.addWidget(self.label_display,7,1,1,6)

        lower_widget = QtWidgets.QWidget()
        lower_widget.setLayout(lower_layout)
        return lower_widget



    def slot_init(self):
        self.button_7.clicked.connect(self.button_open_camera_click)  # 5 打开摄像头
        self.timer_camera.timeout.connect(self.show_camera)                  # 6 摄像头刷新/定时器
        self.button_2.clicked.connect(self.closeCamera)               # 7 关闭摄像头
        self.button_3.clicked.connect(self.takePhoto)                 # 8 拍照
        self.button_5.clicked.connect(self.open_printer_func)
        self.button_6.clicked.connect(self.pagesettings)
        self.button_4.clicked.connect(self.open_picture)

    def open_picture(self):
        self.picedit.show()

    def open_printer_func(self):            # 打印槽函数
        printer_dialog = QPrintDialog(self.printer)
        if printer_dialog.exec_():
            self.edit_n2.print(self.printer)      # 连接打印内容

    def pagesettings(self):
        printsetdialog = QPageSetupDialog(self.printer, self)
        printsetdialog.exec_()

    def open_printer_func2(self):                                   # #
        printer_dialog = QPrintDialog(self.printer)
        if printer_dialog.exec_():
            painter = QtGui.QPainter(self.printer)
            painter.drawPixmap(0, 0, self.label_1)

    def button_open_camera_click(self):
        if self.timer_camera.isActive() == False:
            flag = self.cap.open(self.CAM_NUM)                               ## 9 参数是0,表示打开笔记本的内置摄像头,参数是视频文件路径则打开视频
            if flag == False:
                # 10 flag表示open()成不成功
                msg = QtWidgets.QMessageBox.warning(
                    self, u"Warning", u"请检测相机与电脑是否连接正确",
                    buttons=QtWidgets.QMessageBox.Ok,
                    defaultButton=QtWidgets.QMessageBox.Ok)
            else:
                self.timer_camera.start(30)                                  # 11 定时器开始计时30ms,结果是每过30ms从摄像头中取一帧显示

    def show_camera(self):
        flag, self.image = self.cap.read()                                   # 12 读取一帧数据,flag表示摄像头读取状态,self.image表示摄像头读取的图像矩阵mat类型

        self.image=cv2.flip(self.image, 1)                                   # 13 左右翻转
        show = cv2.cvtColor(self.image, cv2.COLOR_BGR2RGB)                   # 14 视频色彩转换回RGB,这样才是现实的颜色/图像灰度化,灰度化在后面检测时可以降低计算量

        showImage = QtGui.QImage(show.data, show.shape[1], show.shape[0], QtGui.QImage.Format_RGB888)
                                                                             # 15 由于QLabel不能直接显示img类型,需要转化成QImage类型
        self.label_cv2.setPixmap(QtGui.QPixmap.fromImage(showImage))        # 16 往显示视频的Label里 显示QImage
        self.label_cv2.setScaledContents(True)

    # def takePhoto(self):
    #     if self.timer_camera.isActive() != False:
    #         now_time = time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time()))       # 17 获取当前时间及更改格式
    #         print(now_time)
    #
    #         # cv2.imwrite('C:/Users\hopef\Desktop\images'+str(now_time)+'.png',self.image)
    #         cv2.imencode('.jpg', self.image)[1].tofile(r"C:\Users\hopef\Desktop/images.png")
    #         print(r'C:\Users\hopef\Desktop\pic_'+str(now_time)+'.png')
    #         cv2.putText(self.image, 'The picture have saved !' ,
    #                     (int(self.image.shape[1]/2-130), int(self.image.shape[0]/2)),
    #                     cv2.FONT_HERSHEY_SCRIPT_COMPLEX,
    #                     1.0, (255, 0, 0), 1)
    #
    #         self.timer_camera.stop()                # 定时器结束
    #
    #         show = cv2.cvtColor(self.image, cv2.COLOR_BGR2RGB)               # 左右翻转
    #
    #         showImage = QtGui.QImage(show.data, show.shape[1], show.shape[0], QtGui.QImage.Format_RGB888)      # 显示照片
    #         self.label_face.setPixmap(QtGui.QPixmap.fromImage(showImage))
    #         self.label_face.setScaledContents(True)
    def takePhoto(self):
        if self.timer_camera.isActive() != False:
            now_time = time.strftime('%Y-%m-%d-%H-%M-%S', time.localtime(time.time()))
            print(now_time)
            cv2.imwrite('pic_' + str(now_time) + '.jpg', self.image)

            cv2.putText(self.image, 'The picture have saved !',
                        (int(self.image.shape[1] / 2 - 130), int(self.image.shape[0] / 2)),
                        cv2.FONT_HERSHEY_SCRIPT_COMPLEX,
                        1.0, (255, 0, 0), 1)

            self.timer_camera.stop()  # 停止计时

            show = cv2.cvtColor(self.image, cv2.COLOR_BGR2RGB)  # 左右翻转

            showImage = QtGui.QImage(show.data, show.shape[1], show.shape[0], QtGui.QImage.Format_RGB888)
            self.label_cv2.setPixmap(QtGui.QPixmap.fromImage(showImage))
            self.label_cv2.setScaledContents(True)


    def closeCamera(self):
        if self.timer_camera.isActive() != False:                            # 若定时器未启动
            ok = QtWidgets.QPushButton()
            cacel = QtWidgets.QPushButton()

            msg = QtWidgets.QMessageBox(QtWidgets.QMessageBox.Warning, u"关闭", u"是否关闭!")

            msg.addButton(ok,QtWidgets.QMessageBox.ActionRole)
            msg.addButton(cacel, QtWidgets.QMessageBox.RejectRole)
            ok.setText(u'确定')
            cacel.setText(u'取消')

            if msg.exec_() != QtWidgets.QMessageBox.RejectRole:

                if self.cap.isOpened():
                    self.cap.release()                                       # 释放视频流
                if self.timer_camera.isActive():
                    self.timer_camera.stop()
                # self.label_cv2.setText("<html><head/><body><p align=\"center\"><img src=\":/newPrefix/pic/Hint.png\"/><span style=\" font-size:28pt;\">点击打开摄像头</span><br/></p></body></html>")
                self.label_cv2.setText("点击打开摄像头")


class PaintBoard(QWidget):

    def __init__(self, Parent=None):
        super().__init__(Parent)

        self.__InitData()  # 先初始化数据,再初始化界面
        self.__InitView()
        # self.openimage()  # #  打开后导入图像

    def __InitData(self):

        self.__size = QSize(1080, 720)

        # 新建QPixmap作为画板,尺寸为__size
        self.__board = QPixmap(self.__size)
        # self.__board = QPixmap()

        # self.layout = QGridLayout(self)               # 画板中心会出现按钮
        # self.btn = QPushButton('添加')
        # self.layout.addWidget(self.btn)
        # self.setLayout(self.layout)
        # self.btn.clicked.connect(self.openimage)

        self.__board.fill(Qt.white)  # 用白色填充画板

        self.__IsEmpty = True  # 默认为空画板
        self.EraserMode = False  # 默认为禁用橡皮擦模式

        self.__lastPos = QPoint(0, 0)  # 上一次鼠标位置
        self.__currentPos = QPoint(0, 0)  # 当前的鼠标位置

        self.__painter = QPainter()  # 新建绘图工具

        self.__thickness = 2  # 默认画笔粗细为10px
        self.__penColor = QColor("black")  # 设置默认画笔颜色为黑色
        self.__colorList = QColor.colorNames()  # 获取颜色列表

    def openimage(self):  # 2 打开图片的函数
        imgName, imgType = QFileDialog.getOpenFileName(self, "打开图片", "", "*.jpg;;*.png;;All Files(*)")
        self.__board = QPixmap(imgName)
        self.resize(self.__board.width(), self.__board.height())

    def __InitView(self):
        # 设置界面的尺寸为__size
        self.setFixedSize(self.__size)



    def Clear(self):
        # 清空画板
        self.__board.fill(Qt.white)
        self.update()
        self.__IsEmpty = True

    def ChangePenColor(self, color="black"):
        # 改变画笔颜色
        self.__penColor = QColor(color)

    def ChangePenThickness(self, thickness=10):
        # 改变画笔粗细
        self.__thickness = thickness

    def IsEmpty(self):
        # 返回画板是否为空
        return self.__IsEmpty

    def GetContentAsQImage(self):
        # 获取画板内容(返回QImage)
        image = self.__board.toImage()
        return image

    def paintEvent(self, paintEvent):
        # 绘图事件
        # 绘图时必须使用QPainter的实例,此处为__painter
        # 绘图在begin()函数与end()函数间进行
        # begin(param)的参数要指定绘图设备,即把图画在哪里
        # drawPixmap用于绘制QPixmap类型的对象
        self.__painter.begin(self)
        # 0,0为绘图的左上角起点的坐标,__board即要绘制的图
        self.__painter.drawPixmap(0, 0, self.__board)
        self.__painter.end()

    def mousePressEvent(self, mouseEvent):
        # 鼠标按下时,获取鼠标的当前位置保存为上一次位置
        self.__currentPos = mouseEvent.pos()
        self.__lastPos = self.__currentPos

    def mouseMoveEvent(self, mouseEvent):
        # 鼠标移动时,更新当前位置,并在上一个位置和当前位置间画线
        self.__currentPos = mouseEvent.pos()
        self.__painter.begin(self.__board)

        if self.EraserMode == False:
            # 非橡皮擦模式
            self.__painter.setPen(QPen(self.__penColor, self.__thickness))  # 设置画笔颜色,粗细
        else:
            # 橡皮擦模式下画笔为纯白色,粗细为10
            self.__painter.setPen(QPen(Qt.white, 10))

        # 画线
        self.__painter.drawLine(self.__lastPos, self.__currentPos)
        self.__painter.end()
        self.__lastPos = self.__currentPos

        self.update()  # 更新显示

    def mouseReleaseEvent(self, mouseEvent):
        self.__IsEmpty = False  # 画板不再为空


class MainWidget(QWidget):

    def __init__(self, Parent=None):

        super().__init__(Parent)

        self.__InitData()  # 先初始化数据,再初始化界面
        self.__InitView()

    def __InitData(self):

        self.__paintBoard = PaintBoard(self)
        # 获取颜色列表(字符串类型)
        self.__colorList = QColor.colorNames()

    def __InitView(self):
        '''
                  初始化界面
        '''
        # self.setFixedSize(640,480)        # 主页面大小
        self.setWindowTitle("图片编辑器")

        # 新建一个水平布局作为本窗体的主布局
        main_layout = QGridLayout(self)
        # 设置主布局内边距以及控件间距为10px
        main_layout.setSpacing(10)

        # 在主界面左侧放置画板
        main_layout.addWidget(self.__paintBoard, 0, 0, 8, 8)

        # 新建垂直子布局用于放置按键
        sub_layout = QVBoxLayout()

        # 设置此子布局和内部控件的间距为10px
        sub_layout.setContentsMargins(10, 10, 10, 10)

        self.__btn_Clear = QPushButton("清空画板")
        self.__btn_Clear.setParent(self)  # 设置父对象为本界面

        # 将按键按下信号与画板清空函数相关联
        self.__btn_Clear.clicked.connect(self.__paintBoard.Clear)
        sub_layout.addWidget(self.__btn_Clear)

        self.__btn_Quit = QPushButton("退出")
        self.__btn_Quit.setParent(self)  # 设置父对象为本界面
        self.__btn_Quit.clicked.connect(self.close)
        sub_layout.addWidget(self.__btn_Quit)

        self.__btn_Save = QPushButton("保存图片")
        self.__btn_Save.setParent(self)
        self.__btn_Save.clicked.connect(self.on_btn_Save_Clicked)
        sub_layout.addWidget(self.__btn_Save)

        self.__btn_input = QPushButton("导入图片")  # #
        self.__btn_input.setParent(self)
        self.__btn_input.clicked.connect(self.__paintBoard.openimage)
        sub_layout.addWidget(self.__btn_input)

        # self.__cbtn_Eraser = QCheckBox("使用橡皮擦")
        # self.__cbtn_Eraser.setParent(self)
        # self.__cbtn_Eraser.clicked.connect(self.on_cbtn_Eraser_clicked)
        # sub_layout.addWidget(self.__cbtn_Eraser)

        splitter = QSplitter(self)  # 占位符
        sub_layout.addWidget(splitter)

        self.__label_penThickness = QLabel(self)
        self.__label_penThickness.setText("画笔粗细")
        self.__label_penThickness.setFixedHeight(20)
        sub_layout.addWidget(self.__label_penThickness)

        self.__spinBox_penThickness = QSpinBox(self)
        self.__spinBox_penThickness.setMaximum(20)
        self.__spinBox_penThickness.setMinimum(1)
        self.__spinBox_penThickness.setValue(2)  # 默认粗细为10
        self.__spinBox_penThickness.setSingleStep(1)  # 最小变化值为2
        self.__spinBox_penThickness.valueChanged.connect(
            self.on_PenThicknessChange)  # 关联spinBox值变化信号和函数on_PenThicknessChange
        sub_layout.addWidget(self.__spinBox_penThickness)

        self.__label_penColor = QLabel(self)
        self.__label_penColor.setText("颜色选择")
        self.__label_penColor.setFixedHeight(20)
        sub_layout.addWidget(self.__label_penColor)

        self.__comboBox_penColor = QComboBox(self)
        self.__fillColorList(self.__comboBox_penColor)  # 用各种颜色填充下拉列表
        self.__comboBox_penColor.currentIndexChanged.connect(
            self.on_PenColorChange)  # 关联下拉列表的当前索引变更信号与函数on_PenColorChange
        sub_layout.addWidget(self.__comboBox_penColor)

        main_layout.addLayout(sub_layout, 0, 9, 1, 8)  # 将子布局加入主布局

    def __fillColorList(self, comboBox):  # 5. 颜色盒

        index_black = 0
        index = 0
        for color in self.__colorList:
            if color == "black":
                index_black = index
            index += 1
            pix = QPixmap(70, 20)
            pix.fill(QColor(color))
            comboBox.addItem(QIcon(pix), None)
            comboBox.setIconSize(QSize(70, 20))
            comboBox.setSizeAdjustPolicy(QComboBox.AdjustToContents)

        comboBox.setCurrentIndex(index_black)

    # def openimage(self):  # 2 打开图片的函数
    #     imgName, imgType = QFileDialog.getOpenFileName(self, "打开图片", "", "*.jpg;;*.png;;All Files(*)")
    #     self.__board = QPixmap(imgName)
    #     self.resize(self.__board.width(), self.__board.height())

    def on_PenColorChange(self):  # 4. 改变画笔的颜色
        color_index = self.__comboBox_penColor.currentIndex()
        color_str = self.__colorList[color_index]
        self.__paintBoard.ChangePenColor(color_str)

    def on_PenThicknessChange(self):  # 3. 改变画笔的粗细
        penThickness = self.__spinBox_penThickness.value()
        self.__paintBoard.ChangePenThickness(penThickness)

    def on_btn_Save_Clicked(self):  # 2. 保存图片
        savePath = QFileDialog.getSaveFileName(self, 'Save Your Paint', '.\\', '*.jpg;;*.png')
        print(savePath)
        if savePath[0] == "":
            print("Save cancel")
            return
        image = self.__paintBoard.GetContentAsQImage()
        image.save(savePath[0])

if __name__ == '__main__':
    app = QApplication(argv)
    ex = Window()
    qss = '''
             * {color: black}
             QPushButton {background-color: green}
             QLabel {background-color: white}
             .QLineEdit {font: bold 20px}
             QComboBox#cb {color: blue}
             QGroupBox QLabel {color: blue}
             QGroupBox > QLabel {font: 30px}
             '''
    ex.setStyleSheet(qss)
    ex.show()
    exit(app.exec_())

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值