diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..359bb53 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# 默认忽略的文件 +/shelf/ +/workspace.xml diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..8086a31 --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,13 @@ + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..105ce2d --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..d56657a --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..2aed417 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/opencv-pyqt5-master.iml b/.idea/opencv-pyqt5-master.iml new file mode 100644 index 0000000..d0876a7 --- /dev/null +++ b/.idea/opencv-pyqt5-master.iml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/__pycache__/config.cpython-39.pyc b/__pycache__/config.cpython-39.pyc new file mode 100644 index 0000000..942390a Binary files /dev/null and b/__pycache__/config.cpython-39.pyc differ diff --git a/__pycache__/flags.cpython-39.pyc b/__pycache__/flags.cpython-39.pyc new file mode 100644 index 0000000..af50902 Binary files /dev/null and b/__pycache__/flags.cpython-39.pyc differ diff --git a/config.py b/config.py new file mode 100644 index 0000000..3f4fd46 --- /dev/null +++ b/config.py @@ -0,0 +1,108 @@ +from custom.tableWidget import * +from custom.listWidgetItems import * + + +# Implemented functions +items = [ + GrayingItem, + FilterItem, + EqualizeItem, + MorphItem, + GradItem, + ThresholdItem, + EdgeItem, + ContourItem, + HoughLineItem, + GammaItem + +] + +items1 = [ + ImageCutItem, + RotateAnyItem, + RotateLeftItem, + RotateRightItem, + UpDownItem +] + +items2 = [ + ExposureItem, + ContrastItem, + LightItem +] + +items3 = [ + ColorTemperatureItem, + HueItem, + SaturationItem +] + +items4 = [ + HSLRedItem, + HSLOrangeItem, + HSLYellowItem, + HSLGreenItem, + HSLCyanItem, + HSLBlueItem, + HSLPurpleItem +] + +items5 = [ + PixelateItem, + BlurItem + +] + +items6 = [ + CandyStyleTransformItem, + CompositionStyleTransformItem, + FeathersStyleTransformItem, + MuseStyleTransformItem, + MosaicStyleTransformItem, + StarryNightStyleTransformItem, + ScreamStyleTransformItem, + WaveStyleTransformItem, + UdnieStyleTransformItem +] + +items7 = [ + ClarityItem, + NoiseItem +] + +tables = [ + GrayingTableWidget, + FilterTabledWidget, + EqualizeTableWidget, + MorphTabledWidget, + GradTabledWidget, + ThresholdTableWidget, + EdgeTableWidget, + ContourTableWidget, + HoughLineTableWidget, + GammaITabelWidget, + ImageCutTableWidget, + RotateAnyTabelWidget, + RotateLeftTableWidget, + RotateRightTableWidget, + UpDownTableWidget, + ExposureTabelWidget, + ContrastTabelWidget, + LightTableWidget, + ColorTemperatureTabelWidget, + HueTabelWidget, + SaturationTabelWidget, + HSLRedWidget, + HSLOrangeWidget, + HSLYellowWidget, + HSLGreenWidget, + HSLCyanWidget, + HSLBlueWidget, + HSLPurpleWidget, + PixelateTabelWidget, + BlurTabelWidget, + StyleTransformTableWidget, + + +] + diff --git a/custom/__pycache__/graphicsView.cpython-39.pyc b/custom/__pycache__/graphicsView.cpython-39.pyc new file mode 100644 index 0000000..fcf1987 Binary files /dev/null and b/custom/__pycache__/graphicsView.cpython-39.pyc differ diff --git a/custom/__pycache__/listWidgetItems.cpython-39.pyc b/custom/__pycache__/listWidgetItems.cpython-39.pyc new file mode 100644 index 0000000..89d9f45 Binary files /dev/null and b/custom/__pycache__/listWidgetItems.cpython-39.pyc differ diff --git a/custom/__pycache__/listWidgets.cpython-39.pyc b/custom/__pycache__/listWidgets.cpython-39.pyc new file mode 100644 index 0000000..69b299f Binary files /dev/null and b/custom/__pycache__/listWidgets.cpython-39.pyc differ diff --git a/custom/__pycache__/stackedWidget.cpython-39.pyc b/custom/__pycache__/stackedWidget.cpython-39.pyc new file mode 100644 index 0000000..5ee985b Binary files /dev/null and b/custom/__pycache__/stackedWidget.cpython-39.pyc differ diff --git a/custom/__pycache__/tableWidget.cpython-39.pyc b/custom/__pycache__/tableWidget.cpython-39.pyc new file mode 100644 index 0000000..a704510 Binary files /dev/null and b/custom/__pycache__/tableWidget.cpython-39.pyc differ diff --git a/custom/__pycache__/treeView.cpython-39.pyc b/custom/__pycache__/treeView.cpython-39.pyc new file mode 100644 index 0000000..a616e5c Binary files /dev/null and b/custom/__pycache__/treeView.cpython-39.pyc differ diff --git a/custom/__pycache__/treeWidgets.cpython-39.pyc b/custom/__pycache__/treeWidgets.cpython-39.pyc new file mode 100644 index 0000000..8042b33 Binary files /dev/null and b/custom/__pycache__/treeWidgets.cpython-39.pyc differ diff --git a/custom/graphicsView.py b/custom/graphicsView.py new file mode 100644 index 0000000..cbdaf35 --- /dev/null +++ b/custom/graphicsView.py @@ -0,0 +1,87 @@ +import cv2 + +from PyQt5.QtGui import * +from PyQt5.QtCore import * +from PyQt5.QtWidgets import * + + +class GraphicsView(QGraphicsView): + def __init__(self, parent=None): + super(GraphicsView, self).__init__(parent=parent) + self._zoom = 0 + self._empty = True + self._photo = QGraphicsPixmapItem() # 创建pixmapItem对象用于显示图像 + self._scene = QGraphicsScene(self) # 创建存储图元的容器 + self._scene.addItem(self._photo) + self.setScene(self._scene) + self.setAlignment(Qt.AlignCenter) # 居中显示 + self.setDragMode(QGraphicsView.ScrollHandDrag) # 设置拖动 + self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) + self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) + self.setMinimumSize(640, 480) + + def contextMenuEvent(self, event): + if not self.has_photo(): + return + menu = QMenu() + save_action = QAction('另存为', self) + save_action.triggered.connect(self.save_current) # 传递额外值 + menu.addAction(save_action) + menu.exec(QCursor.pos()) + + def save_current(self): + file_name = QFileDialog.getSaveFileName(self, '另存为', './', + 'Image files(*.jpg *.gif *.png)')[0] + print(file_name) + if file_name: + self._photo.pixmap().save(file_name) + + def get_image(self): + if self.has_photo(): + return self._photo.pixmap().toImage() # 获取 + + def has_photo(self): + return not self._empty + + def img_to_pixmap(self, img): + img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # bgr -> rgb + h, w, c = img.shape # 获取图片形状 + image = QImage(img, w, h, 3 * w, QImage.Format_RGB888) + return QPixmap.fromImage(image) + + def update_image(self, img): + self._empty = False + self._photo.setPixmap(self.img_to_pixmap(img)) + + def change_image(self, img): + self.update_image(img) + self.fitInView() + + def fitInView(self, scale=True): + rect = QRectF(self._photo.pixmap().rect()) + if not rect.isNull(): + self.setSceneRect(rect) + if self.has_photo(): + unity = self.transform().mapRect(QRectF(0, 0, 1, 1)) + self.scale(1 / unity.width(), 1 / unity.height()) + viewrect = self.viewport().rect() + scenerect = self.transform().mapRect(rect) + factor = min(viewrect.width() / scenerect.width(), + viewrect.height() / scenerect.height()) + self.scale(factor, factor) + self._zoom = 0 + + def wheelEvent(self, event): + if self.has_photo(): + if event.angleDelta().y() > 0: + factor = 1.25 + self._zoom += 1 + else: + factor = 0.8 + self._zoom -= 1 + if self._zoom > 0: + self.scale(factor, factor) + elif self._zoom == 0: + self.fitInView() + else: + self._zoom = 0 diff --git a/custom/listWidgetItems.py b/custom/listWidgetItems.py new file mode 100644 index 0000000..b148711 --- /dev/null +++ b/custom/listWidgetItems.py @@ -0,0 +1,912 @@ +import numpy as np +import imutils +from PyQt5.QtCore import QSize +from PyQt5.QtGui import QIcon, QColor +from PyQt5.QtWidgets import QListWidgetItem, QPushButton +from flags import * +import cv2 +import random +from PIL import Image + + +class MyItem(QListWidgetItem): + def __init__(self, name=None, parent=None): + super(MyItem, self).__init__(name, parent=parent) + self.setIcon(QIcon('icons/color.png')) + self.setSizeHint(QSize(60, 60)) # size + + def get_params(self): + protected = [v for v in dir(self) if v.startswith('_') and not v.startswith('__')] + param = {} + for v in protected: + param[v.replace('_', '', 1)] = self.__getattribute__(v) + return param + + def update_params(self, param): + for k, v in param.items(): + if '_' + k in dir(self): + self.__setattr__('_' + k, v) + + +class GrayingItem(MyItem): + def __init__(self, parent=None): + super(GrayingItem, self).__init__(' 灰度化 ', parent=parent) + self._mode = BGR2GRAY_COLOR + + def __call__(self, img): + img = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY) + img = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR) + return img + + +class FilterItem(MyItem): + + def __init__(self, parent=None): + super().__init__('平滑处理', parent=parent) + self._ksize = 3 + self._kind = MEAN_FILTER + self._sigmax = 0 + + def __call__(self, img): + if self._kind == MEAN_FILTER: + img = cv2.blur(img, (self._ksize, self._ksize)) + elif self._kind == GAUSSIAN_FILTER: + img = cv2.GaussianBlur(img, (self._ksize, self._ksize), self._sigmax) + elif self._kind == MEDIAN_FILTER: + img = cv2.medianBlur(img, self._ksize) + return img + + +class MorphItem(MyItem): + def __init__(self, parent=None): + super().__init__(' 形态学 ', parent=parent) + self._ksize = 3 + self._op = ERODE_MORPH_OP + self._kshape = RECT_MORPH_SHAPE + + def __call__(self, img): + op = MORPH_OP[self._op] + kshape = MORPH_SHAPE[self._kshape] + kernal = cv2.getStructuringElement(kshape, (self._ksize, self._ksize)) + img = cv2.morphologyEx(img, self._op, kernal) + return img + + +class GradItem(MyItem): + + def __init__(self, parent=None): + super().__init__('图像梯度', parent=parent) + self._kind = SOBEL_GRAD + self._ksize = 3 + self._dx = 1 + self._dy = 0 + + def __call__(self, img): + if self._dx == 0 and self._dy == 0 and self._kind != LAPLACIAN_GRAD: + self.setBackground(QColor(255, 0, 0)) + self.setText('图像梯度 (无效: dx与dy不同时为0)') + else: + self.setBackground(QColor(200, 200, 200)) + self.setText('图像梯度') + if self._kind == SOBEL_GRAD: + img = cv2.Sobel(img, -1, self._dx, self._dy, self._ksize) + elif self._kind == SCHARR_GRAD: + img = cv2.Scharr(img, -1, self._dx, self._dy) + elif self._kind == LAPLACIAN_GRAD: + img = cv2.Laplacian(img, -1) + return img + + +class ThresholdItem(MyItem): + def __init__(self, parent=None): + super().__init__('阈值处理', parent=parent) + self._thresh = 127 + self._maxval = 255 + self._method = BINARY_THRESH_METHOD + + def __call__(self, img): + method = THRESH_METHOD[self._method] + img = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY) + img = cv2.threshold(img, self._thresh, self._thresh, method)[1] + img = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR) + return img + + +class EdgeItem(MyItem): + def __init__(self, parent=None): + super(EdgeItem, self).__init__('边缘检测', parent=parent) + self._thresh1 = 20 + self._thresh2 = 100 + + def __call__(self, img): + img = cv2.Canny(img, threshold1=self._thresh1, threshold2=self._thresh2) + img = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR) + return img + + +class ContourItem(MyItem): + def __init__(self, parent=None): + super(ContourItem, self).__init__('轮廓检测', parent=parent) + self._mode = TREE_CONTOUR_MODE + self._method = SIMPLE_CONTOUR_METHOD + self._bbox = NORMAL_CONTOUR + + def __call__(self, img): + mode = CONTOUR_MODE[self._mode] + method = CONTOUR_METHOD[self._method] + img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) + cnts, _ = cv2.findContours(img, mode, method) + img = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR) + if self._bbox == RECT_CONTOUR: + bboxs = [cv2.boundingRect(cnt) for cnt in cnts] + print(bboxs) + for x, y, w, h in bboxs: + img = cv2.rectangle(img, (x, y), (x + w, y + h), (255, 0, 0), thickness=2) + elif self._bbox == MINRECT_CONTOUR: + bboxs = [np.int0(cv2.boxPoints(cv2.minAreaRect(cnt))) for cnt in cnts] + img = cv2.drawContours(img, bboxs, -1, (255, 0, 0), thickness=2) + elif self._bbox == MINCIRCLE_CONTOUR: + circles = [cv2.minEnclosingCircle(cnt) for cnt in cnts] + print(circles) + for (x, y), r in circles: + img = cv2.circle(img, (int(x), int(y)), int(r), (255, 0, 0), thickness=2) + elif self._bbox == NORMAL_CONTOUR: + img = cv2.drawContours(img, cnts, -1, (255, 0, 0), thickness=2) + + return img + + +class EqualizeItem(MyItem): + def __init__(self, parent=None): + super().__init__(' 均衡化 ', parent=parent) + self._blue = True + self._green = True + self._red = True + + def __call__(self, img): + b, g, r = cv2.split(img) + if self._blue: + b = cv2.equalizeHist(b) + if self._green: + g = cv2.equalizeHist(g) + if self._red: + r = cv2.equalizeHist(r) + return cv2.merge((b, g, r)) + + +class HoughLineItem(MyItem): + def __init__(self, parent=None): + super(HoughLineItem, self).__init__('直线检测', parent=parent) + self._rho = 1 + self._theta = np.pi / 180 + self._thresh = 10 + self._min_length = 20 + self._max_gap = 5 + + def __call__(self, img): + img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) + lines = cv2.HoughLinesP(img, self._rho, self._theta, self._thresh, minLineLength=self._min_length, + maxLineGap=self._max_gap) + img = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR) + if lines is None: + return img + for line in lines: + for x1, y1, x2, y2 in line: + img = cv2.line(img, (x1, y1), (x2, y2), (0, 255, 0), thickness=2) + return img + + +class GammaItem(MyItem): + def __init__(self, parent=None): + super(GammaItem, self).__init__('伽马校正', parent=parent) + self._gamma = 1 + + def __call__(self, img): + gamma_table = [np.power(x / 255.0, self._gamma) * 255.0 for x in range(256)] + gamma_table = np.round(np.array(gamma_table)).astype(np.uint8) + return cv2.LUT(img, gamma_table) + + # 重构: + # 裁剪: + + +class RotateAnyItem(MyItem): # 任意旋转 + def __init__(self, parent=None): + super(RotateAnyItem, self).__init__('任意旋转', parent=parent) + self._angle = 0 + + def __call__(self, img): + img = imutils.rotate_bound(img, self._angle) + return img + + +class RotateLeftItem(MyItem): # 90度旋转 + def __init__(self, parent=None): + super(RotateLeftItem, self).__init__('向左旋转', parent=parent) + + def __call__(self, img): + img = imutils.rotate_bound(img, -90) + return img + + +class RotateRightItem(MyItem): # 90度旋转 + def __init__(self, parent=None): + super(RotateRightItem, self).__init__('向右旋转', parent=parent) + + def __call__(self, img): + img = imutils.rotate_bound(img, 90) + return img + + +class UpDownItem(MyItem): + def __init__(self, parent=None): + super(UpDownItem, self).__init__('上下翻折', parent=parent) + + def __call__(self, img): + img = cv2.flip(img, 0) + return img + + +# 光效 + + +class ExposureItem(MyItem): + def __init__(self, parent=None): + super(ExposureItem, self).__init__('曝光', parent=parent) + self._alpha = 1 + + def __call__(self, img): + blank = np.zeros(img.shape, img.dtype) + img = cv2.addWeighted(img, self._alpha, blank, 1 - self._alpha, 0) + return img + + +class LightItem(MyItem): + def __init__(self, parent=None): + super(LightItem, self).__init__('亮度调节', parent=parent) + self._beta = 0 + + def __call__(self, img): + blank = np.zeros(img.shape, img.dtype) + img = cv2.addWeighted(img, 1, blank, 0, self._beta) + return img + + +class ContrastItem(MyItem): + def __init__(self, parent=None): + super(ContrastItem, self).__init__('对比度调节', parent=parent) + self._alpha = 1 + + def __call__(self, img): + dst = np.ones(img.shape) + img = np.uint8(np.clip(self._alpha * (img - 127 * dst) + 127 * dst, 0, 255)) + return img + + # 色彩: + + +class ColorTemperatureItem(MyItem): + def __init__(self, parent=None): + super(ColorTemperatureItem, self).__init__('色温调节', parent=parent) + self._n = 50 + + def __call__(self, img): + level = self._n / 2 + # src = img.clone() + info = img.shape + row = info[0] + col = info[1] + for i in range(0, row): + for j in range(0, col): + (r, b, g) = img[i, j] + rr = r - level + bb = b - level + gg = g + level + if rr > 255: + rr = 255 + elif rr < 0: + rr = 0 + if bb > 255: + bb = 255 + elif bb < 0: + bb = 0 + if gg > 255: + gg = 255 + elif gg < 0: + gg = 0 + img[i, j] = (rr, bb, gg) + return img + + +class HueItem(MyItem): + def __init__(self, parent=None): + super(HueItem, self).__init__('色调调节', parent=parent) + self._n = 50 + + def __call__(self, img): + level = self._n / 2 + # src = img.clone() + info = img.shape + row = info[0] + col = info[1] + for i in range(0, row): + for j in range(0, col): + (r, b, g) = img[i, j] + rr = r + level + bb = b - level + gg = g + level + if rr > 255: + rr = 255 + elif rr < 0: + rr = 0 + if bb > 255: + bb = 255 + elif bb < 0: + bb = 0 + if gg > 255: + gg = 255 + elif gg < 0: + gg = 0 + img[i, j] = (rr, bb, gg) + return img + + +class SaturationItem(MyItem): + def __init__(self, parent=None): + super(SaturationItem, self).__init__('饱和度调节', parent=parent) + self._x = 0 + + def __call__(self, img): + img_t = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) + # 获取hsv + h, s, v = cv2.split(img_t) + # 增加饱和度 饱和度越低,越接近灰度图像 + s1 = np.clip(cv2.add(s, self._x), 0, 255) + img = np.uint8(cv2.merge((h, s1, v))) + img = cv2.cvtColor(img, cv2.COLOR_HSV2BGR) + return img + + # HSL: + + +class HSLRedItem(MyItem): + def __init__(self, parent=None): + super(HSLRedItem, self).__init__('红色', parent=parent) + self._red_param_s = 1.0 + self._red_param_v = 1.0 + + def __call__(self, img): + img_hsl = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) + info = img.shape + height = info[0] + width = info[1] + value1 = self._red_param_v - 1.0 + value2 = self._red_param_s - 1.0 + for m in range(height): + for w in range(width): + h, s, v = img_hsl[m, w] + b, g, r = img[m, w] + tag = abs((int(b) - int(g)) * (int(g) - int(r))) + if 43 < s < 255 and 46 < v < 255 and tag > 1600: + if 0 < h < 10 or 156 < h < 180: + b = (b + (b - v) * value2) + g = (g + (g - v) * value2) + r = (r + (r - v) * value2) + b = b + value1 * (255 - b) + g = g + value1 * (255 - g) + r = r + value1 * (255 - r) + + img[m, w] = [b, g, r] + + return img + + +class HSLOrangeItem(MyItem): + def __init__(self, parent=None): + super(HSLOrangeItem, self).__init__('橙色', parent=parent) + self._orange_param_s = 1.0 + self._orange_param_v = 1.0 + + def __call__(self, img): + img_hsl = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) + info = img.shape + height = info[0] + width = info[1] + value1 = self._orange_param_v - 1.0 + value2 = self._orange_param_s - 1.0 + for m in range(height): + for w in range(width): + h, s, v = img_hsl[m, w] + b, g, r = img[m, w] + tag = abs((int(b) - int(g)) * (int(g) - int(r))) + if 43 < s < 255 and 46 < v < 255 and tag > 1600: + if 11 < h < 25: + b = (b + (b - v) * value2) + g = (g + (g - v) * value2) + r = (r + (r - v) * value2) + b = b + value1 * (255 - b) + g = g + value1 * (255 - g) + r = r + value1 * (255 - r) + + img[m, w] = [b, g, r] + + return img + + +class HSLYellowItem(MyItem): + def __init__(self, parent=None): + super(HSLYellowItem, self).__init__('黄色', parent=parent) + self._yellow_param_s = 1.0 + self._yellow_param_v = 1.0 + + def __call__(self, img): + img_hsl = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) + info = img.shape + height = info[0] + width = info[1] + value1 = self._yellow_param_v - 1.0 + value2 = self._yellow_param_s - 1.0 + for m in range(height): + for w in range(width): + h, s, v = img_hsl[m, w] + b, g, r = img[m, w] + tag = abs((int(b) - int(g)) * (int(g) - int(r))) + if 43 < s < 255 and 46 < v < 255 and tag > 1600: + if 26 < h < 34: + b = (b + (b - v) * value2) + g = (g + (g - v) * value2) + r = (r + (r - v) * value2) + b = b + value1 * (255 - b) + g = g + value1 * (255 - g) + r = r + value1 * (255 - r) + + img[m, w] = [b, g, r] + + return img + + +class HSLGreenItem(MyItem): + def __init__(self, parent=None): + super(HSLGreenItem, self).__init__('绿色', parent=parent) + self._green_param_s = 1.0 + self._green_param_v = 1.0 + + def __call__(self, img): + img_hsl = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) + info = img.shape + height = info[0] + width = info[1] + value1 = self._green_param_v - 1.0 + value2 = self._green_param_s - 1.0 + for m in range(height): + for w in range(width): + h, s, v = img_hsl[m, w] + b, g, r = img[m, w] + tag = abs((int(b) - int(g)) * (int(g) - int(r))) + if 43 < s < 255 and 46 < v < 255 and tag > 1600: + if 35 < h < 77: + b = (b + (b - v) * value2) + g = (g + (g - v) * value2) + r = (r + (r - v) * value2) + b = b + value1 * (255 - b) + g = g + value1 * (255 - g) + r = r + value1 * (255 - r) + + img[m, w] = [b, g, r] + + return img + + +class HSLCyanItem(MyItem): + def __init__(self, parent=None): + super(HSLCyanItem, self).__init__('青色', parent=parent) + self._cyan_param_s = 1.0 + self._cyan_param_v = 1.0 + + def __call__(self, img): + img_hsl = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) + info = img.shape + height = info[0] + width = info[1] + value1 = self._cyan_param_v - 1.0 + value2 = self._cyan_param_s - 1.0 + for m in range(height): + for w in range(width): + h, s, v = img_hsl[m, w] + b, g, r = img[m, w] + tag = abs((int(b) - int(g)) * (int(g) - int(r))) + if 43 < s < 255 and 46 < v < 255 and tag > 1600: + if 78 < h < 99: + b = (b + (b - v) * value2) + g = (g + (g - v) * value2) + r = (r + (r - v) * value2) + b = b + value1 * (255 - b) + g = g + value1 * (255 - g) + r = r + value1 * (255 - r) + + img[m, w] = [b, g, r] + + return img + + +class HSLBlueItem(MyItem): + def __init__(self, parent=None): + super(HSLBlueItem, self).__init__('蓝色', parent=parent) + self._blue_param_s = 1.0 + self._blue_param_v = 1.0 + + def __call__(self, img): + img_hsl = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) + info = img.shape + height = info[0] + width = info[1] + value1 = self._blue_param_v - 1.0 + value2 = self._blue_param_s - 1.0 + for m in range(height): + for w in range(width): + h, s, v = img_hsl[m, w] + b, g, r = img[m, w] + tag = abs((int(b) - int(g)) * (int(g) - int(r))) + if 43 < s < 255 and 46 < v < 255 and tag > 1600: + if 100 < h < 124: + b = (b + (b - v) * value2) + g = (g + (g - v) * value2) + r = (r + (r - v) * value2) + b = b + value1 * (255 - b) + g = g + value1 * (255 - g) + r = r + value1 * (255 - r) + + img[m, w] = [b, g, r] + + return img + + +class HSLPurpleItem(MyItem): + def __init__(self, parent=None): + super(HSLPurpleItem, self).__init__('紫色', parent=parent) + self._purple_param_s = 1.0 + self._purple_param_v = 1.0 + + def __call__(self, img): + img_hsl = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) + info = img.shape + height = info[0] + width = info[1] + value1 = self._purple_param_v - 1.0 + value2 = self._purple_param_s - 1.0 + for m in range(height): + for w in range(width): + h, s, v = img_hsl[m, w] + b, g, r = img[m, w] + tag = abs((int(b) - int(g)) * (int(g) - int(r))) + if 43 < s < 255 and 46 < v < 255 and tag > 1600: + if 125 < h < 155: + b = (b + (b - v) * value2) + g = (g + (g - v) * value2) + r = (r + (r - v) * value2) + b = b + value1 * (255 - b) + g = g + value1 * (255 - g) + r = r + value1 * (255 - r) + + img[m, w] = [b, g, r] + + return img + + +class PixelateItem(MyItem): + def __init__(self, parent=None): + super(PixelateItem, self).__init__('像素化', parent=parent) + self._size = 100 + + def __call__(self, img): + height, width = img.shape[:2] + + # Desired "pixelated" size + + w, h = (self._size, self._size) + + # Resize input to "pixelated" size + + temp = cv2.resize(img, (w, h), interpolation=cv2.INTER_LINEAR) + + # Initialize output image + + img = cv2.resize(temp, (width, height), interpolation=cv2.INTER_NEAREST) + return img + + +class BlurItem(MyItem): + def __init__(self, parent=None): + super(BlurItem, self).__init__('模糊', parent=parent) + self._size = 5 + + def __call__(self, img): + img = cv2.blur(img, (self._size, self._size)) + return img + + +class CandyStyleTransformItem(MyItem): + def __init__(self, parent=None): + super(CandyStyleTransformItem, self).__init__('candy', parent=parent) + + def __call__(self, img): + net = cv2.dnn.readNetFromTorch("./style/candy.t7") + net.setPreferableBackend(cv2.dnn.DNN_BACKEND_OPENCV) + # img = cv2.imread("D:\\t\\1.jpg") + # res = cv2.resize(img, (500, 300)) + row, column, _ = img.shape + blob = cv2.dnn.blobFromImage(img, 1.0, (column, row), (103.939, 116.779, 123.680), swapRB=False, crop=False) + net.setInput(blob) + out = net.forward() + out = out.reshape(3, out.shape[2], out.shape[3]) + out[0] += 103.939 + out[1] += 116.779 + out[2] += 123.680 + # output = out/255 + out = out.transpose(1, 2, 0) + # output = output.transpose(1, 2, 0) + # cv2.imshow("out", output) + cv2.imwrite("tmp.jpg", out) + out2 = cv2.imread("tmp.jpg") + # out_res = cv2.resize(out, (500, 300)) + return out2 + + +class CompositionStyleTransformItem(MyItem): + def __init__(self, parent=None): + super(CompositionStyleTransformItem, self).__init__('composition', parent=parent) + + def __call__(self, img): + net = cv2.dnn.readNetFromTorch("./style/composition_vii.t7") + net.setPreferableBackend(cv2.dnn.DNN_BACKEND_OPENCV) + # img = cv2.imread("D:\\t\\1.jpg") + # res = cv2.resize(img, (500, 300)) + row, column, _ = img.shape + blob = cv2.dnn.blobFromImage(img, 1.0, (column, row), (103.939, 116.779, 123.680), swapRB=False, crop=False) + net.setInput(blob) + out = net.forward() + out = out.reshape(3, out.shape[2], out.shape[3]) + out[0] += 103.939 + out[1] += 116.779 + out[2] += 123.680 + # output = out/255 + out = out.transpose(1, 2, 0) + # output = output.transpose(1, 2, 0) + # cv2.imshow("out", output) + cv2.imwrite("tmp.jpg", out) + out2 = cv2.imread("tmp.jpg") + # out_res = cv2.resize(out, (500, 300)) + return out2 + + +class FeathersStyleTransformItem(MyItem): + def __init__(self, parent=None): + super(FeathersStyleTransformItem, self).__init__('feathers', parent=parent) + + def __call__(self, img): + net = cv2.dnn.readNetFromTorch("./style/feathers.t7") + net.setPreferableBackend(cv2.dnn.DNN_BACKEND_OPENCV) + # img = cv2.imread("D:\\t\\1.jpg") + # res = cv2.resize(img, (500, 300)) + row, column, _ = img.shape + blob = cv2.dnn.blobFromImage(img, 1.0, (column, row), (103.939, 116.779, 123.680), swapRB=False, crop=False) + net.setInput(blob) + out = net.forward() + out = out.reshape(3, out.shape[2], out.shape[3]) + out[0] += 103.939 + out[1] += 116.779 + out[2] += 123.680 + # output = out/255 + out = out.transpose(1, 2, 0) + # output = output.transpose(1, 2, 0) + # cv2.imshow("out", output) + cv2.imwrite("tmp.jpg", out) + out2 = cv2.imread("tmp.jpg") + # out_res = cv2.resize(out, (500, 300)) + return out2 + + +class MuseStyleTransformItem(MyItem): + def __init__(self, parent=None): + super(MuseStyleTransformItem, self).__init__('la_muse', parent=parent) + + def __call__(self, img): + net = cv2.dnn.readNetFromTorch("./style/la_muse.t7") + net.setPreferableBackend(cv2.dnn.DNN_BACKEND_OPENCV) + # img = cv2.imread("D:\\t\\1.jpg") + # res = cv2.resize(img, (500, 300)) + row, column, _ = img.shape + blob = cv2.dnn.blobFromImage(img, 1.0, (column, row), (103.939, 116.779, 123.680), swapRB=False, crop=False) + net.setInput(blob) + out = net.forward() + out = out.reshape(3, out.shape[2], out.shape[3]) + out[0] += 103.939 + out[1] += 116.779 + out[2] += 123.680 + # output = out/255 + out = out.transpose(1, 2, 0) + # output = output.transpose(1, 2, 0) + # cv2.imshow("out", output) + cv2.imwrite("tmp.jpg", out) + out2 = cv2.imread("tmp.jpg") + # out_res = cv2.resize(out, (500, 300)) + return out2 + + +class MosaicStyleTransformItem(MyItem): + def __init__(self, parent=None): + super(MosaicStyleTransformItem, self).__init__('mosaic', parent=parent) + + def __call__(self, img): + net = cv2.dnn.readNetFromTorch("./style/mosaic.t7") + net.setPreferableBackend(cv2.dnn.DNN_BACKEND_OPENCV) + # img = cv2.imread("D:\\t\\1.jpg") + # res = cv2.resize(img, (500, 300)) + row, column, _ = img.shape + blob = cv2.dnn.blobFromImage(img, 1.0, (column, row), (103.939, 116.779, 123.680), swapRB=False, crop=False) + net.setInput(blob) + out = net.forward() + out = out.reshape(3, out.shape[2], out.shape[3]) + out[0] += 103.939 + out[1] += 116.779 + out[2] += 123.680 + # output = out/255 + out = out.transpose(1, 2, 0) + # output = output.transpose(1, 2, 0) + # cv2.imshow("out", output) + cv2.imwrite("tmp.jpg", out) + out2 = cv2.imread("tmp.jpg") + # out_res = cv2.resize(out, (500, 300)) + return out2 + + +class StarryNightStyleTransformItem(MyItem): + def __init__(self, parent=None): + super(StarryNightStyleTransformItem, self).__init__('starry_night', parent=parent) + + def __call__(self, img): + net = cv2.dnn.readNetFromTorch("./style/starry_night.t7") + net.setPreferableBackend(cv2.dnn.DNN_BACKEND_OPENCV) + # img = cv2.imread("D:\\t\\1.jpg") + # res = cv2.resize(img, (500, 300)) + row, column, _ = img.shape + blob = cv2.dnn.blobFromImage(img, 1.0, (column, row), (103.939, 116.779, 123.680), swapRB=False, crop=False) + net.setInput(blob) + out = net.forward() + out = out.reshape(3, out.shape[2], out.shape[3]) + out[0] += 103.939 + out[1] += 116.779 + out[2] += 123.680 + # output = out/255 + out = out.transpose(1, 2, 0) + # output = output.transpose(1, 2, 0) + # cv2.imshow("out", output) + cv2.imwrite("tmp.jpg", out) + out2 = cv2.imread("tmp.jpg") + # out_res = cv2.resize(out, (500, 300)) + return out2 + + +class ScreamStyleTransformItem(MyItem): + def __init__(self, parent=None): + super(ScreamStyleTransformItem, self).__init__('the_scream', parent=parent) + + def __call__(self, img): + net = cv2.dnn.readNetFromTorch("./style/the_scream.t7") + net.setPreferableBackend(cv2.dnn.DNN_BACKEND_OPENCV) + # img = cv2.imread("D:\\t\\1.jpg") + # res = cv2.resize(img, (500, 300)) + row, column, _ = img.shape + blob = cv2.dnn.blobFromImage(img, 1.0, (column, row), (103.939, 116.779, 123.680), swapRB=False, crop=False) + net.setInput(blob) + out = net.forward() + out = out.reshape(3, out.shape[2], out.shape[3]) + out[0] += 103.939 + out[1] += 116.779 + out[2] += 123.680 + # output = out/255 + out = out.transpose(1, 2, 0) + # output = output.transpose(1, 2, 0) + # cv2.imshow("out", output) + cv2.imwrite("tmp.jpg", out) + out2 = cv2.imread("tmp.jpg") + # out_res = cv2.resize(out, (500, 300)) + return out2 + + +class WaveStyleTransformItem(MyItem): + def __init__(self, parent=None): + super(WaveStyleTransformItem, self).__init__('the_wave', parent=parent) + + def __call__(self, img): + net = cv2.dnn.readNetFromTorch("./style/the_wave.t7") + net.setPreferableBackend(cv2.dnn.DNN_BACKEND_OPENCV) + # img = cv2.imread("D:\\t\\1.jpg") + # res = cv2.resize(img, (500, 300)) + row, column, _ = img.shape + blob = cv2.dnn.blobFromImage(img, 1.0, (column, row), (103.939, 116.779, 123.680), swapRB=False, crop=False) + net.setInput(blob) + out = net.forward() + out = out.reshape(3, out.shape[2], out.shape[3]) + out[0] += 103.939 + out[1] += 116.779 + out[2] += 123.680 + # output = out/255 + out = out.transpose(1, 2, 0) + # output = output.transpose(1, 2, 0) + # cv2.imshow("out", output) + cv2.imwrite("tmp.jpg", out) + out2 = cv2.imread("tmp.jpg") + # out_res = cv2.resize(out, (500, 300)) + return out2 + + +class UdnieStyleTransformItem(MyItem): + def __init__(self, parent=None): + super(UdnieStyleTransformItem, self).__init__('udnie', parent=parent) + + def __call__(self, img): + net = cv2.dnn.readNetFromTorch("./style/udnie.t7") + net.setPreferableBackend(cv2.dnn.DNN_BACKEND_OPENCV) + # img = cv2.imread("D:\\t\\1.jpg") + # res = cv2.resize(img, (500, 300)) + row, column, _ = img.shape + blob = cv2.dnn.blobFromImage(img, 1.0, (column, row), (103.939, 116.779, 123.680), swapRB=False, crop=False) + net.setInput(blob) + out = net.forward() + out = out.reshape(3, out.shape[2], out.shape[3]) + out[0] += 103.939 + out[1] += 116.779 + out[2] += 123.680 + # output = out/255 + out = out.transpose(1, 2, 0) + # output = output.transpose(1, 2, 0) + # cv2.imshow("out", output) + cv2.imwrite("tmp.jpg", out) + out2 = cv2.imread("tmp.jpg") + # out_res = cv2.resize(out, (500, 300)) + return out2 + + +class ClarityItem(MyItem): + def __init__(self, parent=None): + super(ClarityItem, self).__init__('锐化', parent=parent) + + def __call__(self, img): + kernel = np.array([[0, -1, 0], [-1, 5, -1], [0, -1, 0]], np.float32) + dst = cv2.filter2D(img, -1, kernel=kernel) + return dst + + +class NoiseItem(MyItem): + def __init__(self, parent=None): + super(NoiseItem, self).__init__('噪点', parent=parent) + + def __call__(self, img): + num = int(0.02 * img.shape[0] * img.shape[1]) # 椒盐噪声点数量 + random.randint(0, img.shape[0]) + img2 = img.copy() + for i in range(num): + X = random.randint(0, img2.shape[0] - 1) # 从0到图像长度之间的一个随机整数,因为是闭区间所以-1 + Y = random.randint(0, img2.shape[1] - 1) + if random.randint(0, 1) == 0: # 黑白色概率55开 + img2[X, Y] = (255, 255, 255) # 白色 + else: + img2[X, Y] = (0, 0, 0) # 黑色 + return img2 + + +class ImageCutItem(MyItem): + def __init__(self, parent=None): + super(ImageCutItem, self).__init__('裁剪', parent=parent) + self._x1 = 0 + self._x2 = 300 + self._y1 = 200 + self._y2 = 600 + + def __call__(self, img): + dst = img[self._y1:self._y2, self._x1:self._x2] + return dst + + + diff --git a/custom/listWidgets.py b/custom/listWidgets.py new file mode 100644 index 0000000..4c955a5 --- /dev/null +++ b/custom/listWidgets.py @@ -0,0 +1,310 @@ +from PyQt5.QtGui import * +from PyQt5.QtCore import * +from PyQt5.QtWidgets import * + +from config import items, items1, items2, items3, items4, items5, items6, items7 + + +class MyListWidget(QListWidget): + def __init__(self, parent=None): + super().__init__(parent=parent) + self.mainwindow = parent + self.setDragEnabled(True) + # 选中不显示虚线 + # self.setEditTriggers(QAbstractItemView.NoEditTriggers) + self.setFocusPolicy(Qt.NoFocus) + + +class UsedListWidget(MyListWidget): + def __init__(self, parent=None): + super().__init__(parent=parent) + self.setAcceptDrops(True) + self.setFlow(QListView.TopToBottom) # 设置列表方向 + self.setDefaultDropAction(Qt.MoveAction) # 设置拖放为移动而不是复制一个 + self.setDragDropMode(QAbstractItemView.InternalMove) # 设置拖放模式, 内部拖放 + self.itemClicked.connect(self.show_attr) + self.setMinimumWidth(200) + + self.move_item = None + + def contextMenuEvent(self, e): + # 右键菜单事件 + item = self.itemAt(self.mapFromGlobal(QCursor.pos())) + if not item: + return # 判断是否是空白区域 + menu = QMenu() + delete_action = QAction('删除', self) + delete_action.triggered.connect(lambda: self.delete_item(item)) # 传递额外值 + menu.addAction(delete_action) + menu.exec(QCursor.pos()) + + def delete_item(self, item): + # 删除操作 + self.takeItem(self.row(item)) + self.mainwindow.update_image() # 更新frame + self.mainwindow.dock_attr.close() + + def dropEvent(self, event): + super().dropEvent(event) + self.mainwindow.update_image() + + def show_attr(self): + item = self.itemAt(self.mapFromGlobal(QCursor.pos())) + if not item: + return + param = item.get_params() # 获取当前item的属性 + if type(item) in items: + index = items.index(type(item)) # 获取item对应的table索引 + self.mainwindow.stackedWidget.setCurrentIndex(index) + self.mainwindow.stackedWidget.currentWidget().update_params(param) # 更新对应的table + self.mainwindow.dock_attr.show() + if type(item) in items1: + index = items1.index(type(item)) # 获取item对应的table索引 + self.mainwindow.stackedWidget.setCurrentIndex(index + 10) + self.mainwindow.stackedWidget.currentWidget().update_params(param) # 更新对应的table + self.mainwindow.dock_attr.show() + if type(item) in items2: + index = items2.index(type(item)) # 获取item对应的table索引 + self.mainwindow.stackedWidget.setCurrentIndex(index + 15) + self.mainwindow.stackedWidget.currentWidget().update_params(param) # 更新对应的table + self.mainwindow.dock_attr.show() + if type(item) in items3: + index = items3.index(type(item)) # 获取item对应的table索引 + self.mainwindow.stackedWidget.setCurrentIndex(index + 18) + self.mainwindow.stackedWidget.currentWidget().update_params(param) # 更新对应的table + self.mainwindow.dock_attr.show() + if type(item) in items4: + index = items4.index(type(item)) # 获取item对应的table索引 + self.mainwindow.stackedWidget.setCurrentIndex(index + 21) + self.mainwindow.stackedWidget.currentWidget().update_params(param) # 更新对应的table + self.mainwindow.dock_attr.show() + if type(item) in items5: + index = items5.index(type(item)) # 获取item对应的table索引 + self.mainwindow.stackedWidget.setCurrentIndex(index + 28) + self.mainwindow.stackedWidget.currentWidget().update_params(param) # 更新对应的table + self.mainwindow.dock_attr.show() + if type(item) in items6: # 获取item对应的table索引 + self.mainwindow.stackedWidget.setCurrentIndex(30) + self.mainwindow.stackedWidget.currentWidget().update_params(param) # 更新对应的table + self.mainwindow.dock_attr.show() + if type(item) in items7: # 获取item对应的table索引 + self.mainwindow.stackedWidget.setCurrentIndex(30) + self.mainwindow.stackedWidget.currentWidget().update_params(param) # 更新对应的table + self.mainwindow.dock_attr.show() + + +class FuncListWidget(MyListWidget): + def __init__(self, parent=None): + super().__init__(parent=parent) + self.setFixedHeight(64 * 3) + self.setFlow(QListView.LeftToRight) # 设置列表方向 + self.setViewMode(QListView.IconMode) # 设置列表模式 + self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) # 关掉滑动条 + self.setAcceptDrops(False) + for itemType in items: + self.addItem(itemType()) + self.itemClicked.connect(self.add_used_function) + + def add_used_function(self): + func_item = self.currentItem() + if type(func_item) in items: + use_item = type(func_item)() + self.mainwindow.useListWidget.addItem(use_item) + self.mainwindow.update_image() + + def enterEvent(self, event): + self.setCursor(Qt.PointingHandCursor) + + def leaveEvent(self, event): + self.setCursor(Qt.ArrowCursor) + self.setCurrentRow(-1) # 取消选中状态 + + +class FuncListWidget1(MyListWidget): + def __init__(self, parent=None): + super().__init__(parent=parent) + self.setFixedHeight(64 * 3) + self.setFlow(QListView.LeftToRight) # 设置列表方向 + self.setViewMode(QListView.IconMode) # 设置列表模式 + self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) # 关掉滑动条 + self.setAcceptDrops(False) + for itemType in items1: + self.addItem(itemType()) + self.itemClicked.connect(self.add_used_function) + + def add_used_function(self): + func_item = self.currentItem() + if type(func_item) in items1: + use_item = type(func_item)() + self.mainwindow.useListWidget.addItem(use_item) + self.mainwindow.update_image() + + def enterEvent(self, event): + self.setCursor(Qt.PointingHandCursor) + + def leaveEvent(self, event): + self.setCursor(Qt.ArrowCursor) + self.setCurrentRow(-1) # 取消选中状态 + + +class FuncListWidget2(MyListWidget): + def __init__(self, parent=None): + super().__init__(parent=parent) + self.setFixedHeight(64 * 3) + self.setFlow(QListView.LeftToRight) # 设置列表方向 + self.setViewMode(QListView.IconMode) # 设置列表模式 + self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) # 关掉滑动条 + self.setAcceptDrops(False) + for itemType in items2: + self.addItem(itemType()) + self.itemClicked.connect(self.add_used_function) + + def add_used_function(self): + func_item = self.currentItem() + if type(func_item) in items2: + use_item = type(func_item)() + self.mainwindow.useListWidget.addItem(use_item) + self.mainwindow.update_image() + + def enterEvent(self, event): + self.setCursor(Qt.PointingHandCursor) + + def leaveEvent(self, event): + self.setCursor(Qt.ArrowCursor) + self.setCurrentRow(-1) # 取消选中状态 + + +class FuncListWidget3(MyListWidget): + def __init__(self, parent=None): + super().__init__(parent=parent) + self.setFixedHeight(64 * 3) + self.setFlow(QListView.LeftToRight) # 设置列表方向 + self.setViewMode(QListView.IconMode) # 设置列表模式 + self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) # 关掉滑动条 + self.setAcceptDrops(False) + for itemType in items3: + self.addItem(itemType()) + self.itemClicked.connect(self.add_used_function) + + def add_used_function(self): + func_item = self.currentItem() + if type(func_item) in items3: + use_item = type(func_item)() + self.mainwindow.useListWidget.addItem(use_item) + self.mainwindow.update_image() + + def enterEvent(self, event): + self.setCursor(Qt.PointingHandCursor) + + def leaveEvent(self, event): + self.setCursor(Qt.ArrowCursor) + self.setCurrentRow(-1) # 取消选中状态 + + +class FuncListWidget4(MyListWidget): + def __init__(self, parent=None): + super().__init__(parent=parent) + self.setFixedHeight(64 * 3) + self.setFlow(QListView.LeftToRight) # 设置列表方向 + self.setViewMode(QListView.IconMode) # 设置列表模式 + self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) # 关掉滑动条 + self.setAcceptDrops(False) + for itemType in items4: + self.addItem(itemType()) + self.itemClicked.connect(self.add_used_function) + + def add_used_function(self): + func_item = self.currentItem() + if type(func_item) in items4: + use_item = type(func_item)() + self.mainwindow.useListWidget.addItem(use_item) + self.mainwindow.update_image() + + def enterEvent(self, event): + self.setCursor(Qt.PointingHandCursor) + + def leaveEvent(self, event): + self.setCursor(Qt.ArrowCursor) + self.setCurrentRow(-1) # 取消选中状态 + + +class FuncListWidget5(MyListWidget): + def __init__(self, parent=None): + super().__init__(parent=parent) + self.setFixedHeight(64 * 3) + self.setFlow(QListView.LeftToRight) # 设置列表方向 + self.setViewMode(QListView.IconMode) # 设置列表模式 + self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) # 关掉滑动条 + self.setAcceptDrops(False) + for itemType in items5: + self.addItem(itemType()) + self.itemClicked.connect(self.add_used_function) + + def add_used_function(self): + func_item = self.currentItem() + if type(func_item) in items5: + use_item = type(func_item)() + self.mainwindow.useListWidget.addItem(use_item) + self.mainwindow.update_image() + + def enterEvent(self, event): + self.setCursor(Qt.PointingHandCursor) + + def leaveEvent(self, event): + self.setCursor(Qt.ArrowCursor) + self.setCurrentRow(-1) # 取消选中状态 + + +class FuncListWidget6(MyListWidget): + def __init__(self, parent=None): + super().__init__(parent=parent) + self.setFixedHeight(64 * 3) + self.setFlow(QListView.LeftToRight) # 设置列表方向 + self.setViewMode(QListView.IconMode) # 设置列表模式 + self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) # 关掉滑动条 + self.setAcceptDrops(False) + for itemType in items6: + self.addItem(itemType()) + self.itemClicked.connect(self.add_used_function) + + def add_used_function(self): + func_item = self.currentItem() + if type(func_item) in items6: + use_item = type(func_item)() + self.mainwindow.useListWidget.addItem(use_item) + self.mainwindow.update_image() + + def enterEvent(self, event): + self.setCursor(Qt.PointingHandCursor) + + def leaveEvent(self, event): + self.setCursor(Qt.ArrowCursor) + self.setCurrentRow(-1) # 取消选中状态 + + +class FuncListWidget7(MyListWidget): + def __init__(self, parent=None): + super().__init__(parent=parent) + self.setFixedHeight(64 * 3) + self.setFlow(QListView.LeftToRight) # 设置列表方向 + self.setViewMode(QListView.IconMode) # 设置列表模式 + self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) # 关掉滑动条 + self.setAcceptDrops(False) + for itemType in items7: + self.addItem(itemType()) + self.itemClicked.connect(self.add_used_function) + + def add_used_function(self): + func_item = self.currentItem() + if type(func_item) in items7: + use_item = type(func_item)() + self.mainwindow.useListWidget.addItem(use_item) + self.mainwindow.update_image() + + def enterEvent(self, event): + self.setCursor(Qt.PointingHandCursor) + + def leaveEvent(self, event): + self.setCursor(Qt.ArrowCursor) + self.setCurrentRow(-1) # 取消选中状态 + diff --git a/custom/stackedWidget.py b/custom/stackedWidget.py new file mode 100644 index 0000000..e7290a9 --- /dev/null +++ b/custom/stackedWidget.py @@ -0,0 +1,10 @@ +from custom.tableWidget import * +from config import tables + + +class StackedWidget(QStackedWidget): + def __init__(self, parent): + super().__init__(parent=parent) + for table in tables: + self.addWidget(table(parent=parent)) + self.setMinimumWidth(200) diff --git a/custom/styleSheet.qss b/custom/styleSheet.qss new file mode 100644 index 0000000..a244671 --- /dev/null +++ b/custom/styleSheet.qss @@ -0,0 +1,86 @@ +*{ + font-family: 微软雅黑; + color: #BBBBBB; + background-color: #2F2F2F; +} + +/* 设置目录树样式 */ +QTreeView{ + show-decoration-selected: 1; +} +QTreeView::item{ + height: 30px; +} +QTreeView::item:hover, QTreeView::branch:hover{ + background: #4B6EAF; +} +QTreeView::item:selected, QTreeView::branch:selected{ + background: #4B6EAF; +} +QTreeView::branch{ + color: #BBBBBB; +} +QTreeView::branch:has-children:!has-siblings:closed, +QTreeView::branch:closed:has-children:has-siblings { + border-image: none; + image: url(icons/branch-close.png); +} +QTreeView::branch:open:has-children:!has-siblings, +QTreeView::branch:open:has-children:has-siblings { + border-image: none; + image: url(icons/branch-open.png); +} + +/* 设置标签样式 */ +QLabel{ + font-size: 18px; + border: 1px solid #BBBBBB; + border-width: 1px 1px 0px 1px; +} + +/* 设置视图样式 */ +QGraphicsView{ + border: 1px solid #BBBBBB; + background-color: #444444; +} + +/* 设置列表样式 */ +QListWidget::Item{ + border: 1px solid #BBBBBB; + font-size: 20px; + background: #717678; + color: #DDDDDD; +} + +QListWidget::Item:hover{ + background: #4B6EAF; +} + +FuncListWidget::Item{ + border-style: inset; + border-radius: 8px; + border: 1px solid #999999; + margin:0px 1px 0px 0px +} + +UsedListWidget::Item{ + border: 2px solid #999999; + margin:0px 0px 1px 0px +} + +UsedListWidget::Item:selected{ + background: #99CCFF; +} + + +/* 设置表格样式 */ +QTableWidget{ + alternate-background-color: #444444; +} + + +QToolButton:hover{ + background: #4B6EAF; +} + + diff --git a/custom/tableWidget.py b/custom/tableWidget.py new file mode 100644 index 0000000..f8238bd --- /dev/null +++ b/custom/tableWidget.py @@ -0,0 +1,690 @@ +from PyQt5.QtWidgets import * +from PyQt5.QtCore import * + + +class TableWidget(QTableWidget): + def __init__(self, parent=None): + super(TableWidget, self).__init__(parent=parent) + self.mainwindow = parent + self.setShowGrid(True) # 显示网格 + self.setAlternatingRowColors(True) # 隔行显示颜色 + self.setEditTriggers(QAbstractItemView.NoEditTriggers) + self.horizontalHeader().setVisible(False) + self.verticalHeader().setVisible(False) + self.horizontalHeader().sectionResizeMode(QHeaderView.Stretch) + self.verticalHeader().sectionResizeMode(QHeaderView.Stretch) + self.horizontalHeader().setStretchLastSection(True) + self.setFocusPolicy(Qt.NoFocus) + + def signal_connect(self): + for spinbox in self.findChildren(QSpinBox): + spinbox.valueChanged.connect(self.update_item) + for doublespinbox in self.findChildren(QDoubleSpinBox): + doublespinbox.valueChanged.connect(self.update_item) + for combox in self.findChildren(QComboBox): + combox.currentIndexChanged.connect(self.update_item) + for checkbox in self.findChildren(QCheckBox): + checkbox.stateChanged.connect(self.update_item) + + def update_item(self): + param = self.get_params() + self.mainwindow.useListWidget.currentItem().update_params(param) + self.mainwindow.update_image() + + def update_params(self, param=None): + for key in param.keys(): + box = self.findChild(QWidget, name=key) + if isinstance(box, QSpinBox) or isinstance(box, QDoubleSpinBox): + box.setValue(param[key]) + elif isinstance(box, QComboBox): + box.setCurrentIndex(param[key]) + elif isinstance(box, QCheckBox): + box.setChecked(param[key]) + + def get_params(self): + param = {} + for spinbox in self.findChildren(QSpinBox): + param[spinbox.objectName()] = spinbox.value() + for doublespinbox in self.findChildren(QDoubleSpinBox): + param[doublespinbox.objectName()] = doublespinbox.value() + for combox in self.findChildren(QComboBox): + param[combox.objectName()] = combox.currentIndex() + for combox in self.findChildren(QCheckBox): + param[combox.objectName()] = combox.isChecked() + return param + + +class GrayingTableWidget(TableWidget): + def __init__(self, parent=None): + super(GrayingTableWidget, self).__init__(parent=parent) + + +class FilterTabledWidget(TableWidget): + def __init__(self, parent=None): + super(FilterTabledWidget, self).__init__(parent=parent) + + self.kind_comBox = QComboBox() + self.kind_comBox.addItems(['均值滤波', '高斯滤波', '中值滤波']) + self.kind_comBox.setObjectName('kind') + + self.ksize_spinBox = QSpinBox() + self.ksize_spinBox.setObjectName('ksize') + self.ksize_spinBox.setMinimum(1) + self.ksize_spinBox.setSingleStep(2) + + self.setColumnCount(2) + self.setRowCount(2) + self.setItem(0, 0, QTableWidgetItem('类型')) + self.setCellWidget(0, 1, self.kind_comBox) + self.setItem(1, 0, QTableWidgetItem('核大小')) + self.setCellWidget(1, 1, self.ksize_spinBox) + + self.signal_connect() + + +class MorphTabledWidget(TableWidget): + def __init__(self, parent=None): + super(MorphTabledWidget, self).__init__(parent=parent) + + self.op_comBox = QComboBox() + self.op_comBox.addItems(['腐蚀操作', '膨胀操作', '开操作', '闭操作', '梯度操作', '顶帽操作', '黑帽操作']) + self.op_comBox.setObjectName('op') + + self.ksize_spinBox = QSpinBox() + self.ksize_spinBox.setMinimum(1) + self.ksize_spinBox.setSingleStep(2) + self.ksize_spinBox.setObjectName('ksize') + + self.kshape_comBox = QComboBox() + self.kshape_comBox.addItems(['方形', '十字形', '椭圆形']) + self.kshape_comBox.setObjectName('kshape') + + self.setColumnCount(2) + self.setRowCount(3) + self.setItem(0, 0, QTableWidgetItem('类型')) + self.setCellWidget(0, 1, self.op_comBox) + self.setItem(1, 0, QTableWidgetItem('核大小')) + self.setCellWidget(1, 1, self.ksize_spinBox) + self.setItem(2, 0, QTableWidgetItem('核形状')) + self.setCellWidget(2, 1, self.kshape_comBox) + self.signal_connect() + + +class GradTabledWidget(TableWidget): + def __init__(self, parent=None): + super(GradTabledWidget, self).__init__(parent=parent) + + self.kind_comBox = QComboBox() + self.kind_comBox.addItems(['Sobel算子', 'Scharr算子', 'Laplacian算子']) + self.kind_comBox.setObjectName('kind') + + self.ksize_spinBox = QSpinBox() + self.ksize_spinBox.setMinimum(1) + self.ksize_spinBox.setSingleStep(2) + self.ksize_spinBox.setObjectName('ksize') + + self.dx_spinBox = QSpinBox() + self.dx_spinBox.setMaximum(1) + self.dx_spinBox.setMinimum(0) + self.dx_spinBox.setSingleStep(1) + self.dx_spinBox.setObjectName('dx') + + self.dy_spinBox = QSpinBox() + self.dy_spinBox.setMaximum(1) + self.dy_spinBox.setMinimum(0) + self.dy_spinBox.setSingleStep(1) + self.dy_spinBox.setObjectName('dy') + + self.setColumnCount(2) + self.setRowCount(4) + + self.setItem(0, 0, QTableWidgetItem('类型')) + self.setCellWidget(0, 1, self.kind_comBox) + self.setItem(1, 0, QTableWidgetItem('核大小')) + self.setCellWidget(1, 1, self.ksize_spinBox) + self.setItem(2, 0, QTableWidgetItem('x方向')) + self.setCellWidget(2, 1, self.dx_spinBox) + self.setItem(3, 0, QTableWidgetItem('y方向')) + self.setCellWidget(3, 1, self.dy_spinBox) + + self.signal_connect() + + +class ThresholdTableWidget(TableWidget): + def __init__(self, parent=None): + super(ThresholdTableWidget, self).__init__(parent=parent) + + self.thresh_spinBox = QSpinBox() + self.thresh_spinBox.setObjectName('thresh') + self.thresh_spinBox.setMaximum(255) + self.thresh_spinBox.setMinimum(0) + self.thresh_spinBox.setSingleStep(1) + + self.maxval_spinBox = QSpinBox() + self.maxval_spinBox.setObjectName('maxval') + self.maxval_spinBox.setMaximum(255) + self.maxval_spinBox.setMinimum(0) + self.maxval_spinBox.setSingleStep(1) + + self.method_comBox = QComboBox() + self.method_comBox.addItems(['二进制阈值化', '反二进制阈值化', '截断阈值化', '阈值化为0', '反阈值化为0', '大津算法']) + self.method_comBox.setObjectName('method') + + self.setColumnCount(2) + self.setRowCount(3) + + self.setItem(0, 0, QTableWidgetItem('类型')) + self.setCellWidget(0, 1, self.method_comBox) + self.setItem(1, 0, QTableWidgetItem('阈值')) + self.setCellWidget(1, 1, self.thresh_spinBox) + self.setItem(2, 0, QTableWidgetItem('最大值')) + self.setCellWidget(2, 1, self.maxval_spinBox) + + self.signal_connect() + + +class EdgeTableWidget(TableWidget): + def __init__(self, parent=None): + super(EdgeTableWidget, self).__init__(parent=parent) + + self.thresh1_spinBox = QSpinBox() + self.thresh1_spinBox.setMinimum(0) + self.thresh1_spinBox.setMaximum(255) + self.thresh1_spinBox.setSingleStep(1) + self.thresh1_spinBox.setObjectName('thresh1') + + self.thresh2_spinBox = QSpinBox() + self.thresh2_spinBox.setMinimum(0) + self.thresh2_spinBox.setMaximum(255) + self.thresh2_spinBox.setSingleStep(1) + self.thresh2_spinBox.setObjectName('thresh2') + + self.setColumnCount(2) + self.setRowCount(2) + + self.setItem(0, 0, QTableWidgetItem('阈值1')) + self.setCellWidget(0, 1, self.thresh1_spinBox) + self.setItem(1, 0, QTableWidgetItem('阈值2')) + self.setCellWidget(1, 1, self.thresh2_spinBox) + self.signal_connect() + + +class ImageCutTableWidget(TableWidget): + def __init__(self, parent=None): + super(ImageCutTableWidget, self).__init__(parent=parent) + + self.x1_spinBox = QSpinBox() + self.x1_spinBox.setMinimum(1) + self.x1_spinBox.setMaximum(5000) + self.x1_spinBox.setSingleStep(1) + self.x1_spinBox.setObjectName('x1') + + self.y1_spinBox = QSpinBox() + self.y1_spinBox.setMinimum(1) + self.y1_spinBox.setMaximum(5000) + self.y1_spinBox.setSingleStep(1) + self.y1_spinBox.setObjectName('y1') + + self.x2_spinBox = QSpinBox() + self.x2_spinBox.setMinimum(1) + self.x2_spinBox.setMaximum(5000) + self.x2_spinBox.setSingleStep(1) + self.x2_spinBox.setObjectName('x2') + + self.y2_spinBox = QSpinBox() + self.y2_spinBox.setMinimum(1) + self.y2_spinBox.setMaximum(5000) + self.y2_spinBox.setSingleStep(1) + self.y2_spinBox.setObjectName('y2') + + self.setColumnCount(4) + self.setRowCount(2) + + self.setItem(0, 0, QTableWidgetItem('x1')) + self.setCellWidget(0, 1, self.x1_spinBox) + self.setItem(1, 0, QTableWidgetItem('y1')) + self.setCellWidget(1, 1, self.y1_spinBox) + self.setItem(2, 0, QTableWidgetItem('x2')) + self.setCellWidget(2, 1, self.x2_spinBox) + self.setItem(3, 0, QTableWidgetItem('y2')) + self.setCellWidget(3, 1, self.y2_spinBox) + self.signal_connect() + + +class ContourTableWidget(TableWidget): + def __init__(self, parent=None): + super(ContourTableWidget, self).__init__(parent=parent) + + self.bbox_comBox = QComboBox() + self.bbox_comBox.addItems(['正常轮廓', '外接矩形', '最小外接矩形', '最小外接圆']) + self.bbox_comBox.setObjectName('bbox') + + self.mode_comBox = QComboBox() + self.mode_comBox.addItems(['外轮廓', '轮廓列表', '外轮廓与内孔', '轮廓等级树']) + self.mode_comBox.setObjectName('mode') + + self.method_comBox = QComboBox() + self.method_comBox.addItems(['无近似', '简易近似']) + self.method_comBox.setObjectName('method') + + self.setColumnCount(2) + self.setRowCount(3) + + self.setItem(0, 0, QTableWidgetItem('轮廓模式')) + self.setCellWidget(0, 1, self.mode_comBox) + self.setItem(1, 0, QTableWidgetItem('轮廓近似')) + self.setCellWidget(1, 1, self.method_comBox) + self.setItem(2, 0, QTableWidgetItem('边界模式')) + self.setCellWidget(2, 1, self.bbox_comBox) + self.signal_connect() + + +class EqualizeTableWidget(TableWidget): + def __init__(self, parent=None): + super(EqualizeTableWidget, self).__init__(parent=parent) + self.red_checkBox = QCheckBox() + self.red_checkBox.setObjectName('red') + self.red_checkBox.setTristate(False) + self.blue_checkBox = QCheckBox() + self.blue_checkBox.setObjectName('blue') + self.blue_checkBox.setTristate(False) + self.green_checkBox = QCheckBox() + self.green_checkBox.setObjectName('green') + self.green_checkBox.setTristate(False) + + self.setColumnCount(2) + self.setRowCount(3) + + self.setItem(0, 0, QTableWidgetItem('R通道')) + self.setCellWidget(0, 1, self.red_checkBox) + self.setItem(1, 0, QTableWidgetItem('G通道')) + self.setCellWidget(1, 1, self.green_checkBox) + self.setItem(2, 0, QTableWidgetItem('B通道')) + self.setCellWidget(2, 1, self.blue_checkBox) + self.signal_connect() + + +class HoughLineTableWidget(TableWidget): + def __init__(self, parent=None): + super(HoughLineTableWidget, self).__init__(parent=parent) + + self.thresh_spinBox = QSpinBox() + self.thresh_spinBox.setMinimum(0) + self.thresh_spinBox.setSingleStep(1) + self.thresh_spinBox.setObjectName('thresh') + + self.min_length_spinBox = QSpinBox() + self.min_length_spinBox.setMinimum(0) + self.min_length_spinBox.setSingleStep(1) + self.min_length_spinBox.setObjectName('min_length') + + self.max_gap_spinbox = QSpinBox() + self.max_gap_spinbox.setMinimum(0) + self.max_gap_spinbox.setSingleStep(1) + self.max_gap_spinbox.setObjectName('max_gap') + + self.setColumnCount(2) + self.setRowCount(3) + + self.setItem(0, 0, QTableWidgetItem('交点阈值')) + self.setCellWidget(0, 1, self.thresh_spinBox) + self.setItem(1, 0, QTableWidgetItem('最小长度')) + self.setCellWidget(1, 1, self.min_length_spinBox) + self.setItem(2, 0, QTableWidgetItem('最大间距')) + self.setCellWidget(2, 1, self.max_gap_spinbox) + self.signal_connect() + + +class LightTableWidget(TableWidget): + def __init__(self, parent=None): + super(LightTableWidget, self).__init__(parent=parent) + + self.alpha_spinBox = QDoubleSpinBox() + self.alpha_spinBox.setMinimum(0) + self.alpha_spinBox.setMaximum(3) + self.alpha_spinBox.setSingleStep(0.1) + self.alpha_spinBox.setObjectName('alpha') + + self.beta_spinbox = QSpinBox() + self.beta_spinbox.setMinimum(0) + self.beta_spinbox.setSingleStep(1) + self.beta_spinbox.setObjectName('beta') + + self.setColumnCount(2) + self.setRowCount(2) + + self.setItem(0, 0, QTableWidgetItem('alpha')) + self.setCellWidget(0, 1, self.alpha_spinBox) + self.setItem(1, 0, QTableWidgetItem('beta')) + self.setCellWidget(1, 1, self.beta_spinbox) + self.signal_connect() + + +class GammaITabelWidget(TableWidget): + def __init__(self, parent=None): + super(GammaITabelWidget, self).__init__(parent=parent) + self.gamma_spinbox = QDoubleSpinBox() + self.gamma_spinbox.setMinimum(0) + self.gamma_spinbox.setSingleStep(0.1) + self.gamma_spinbox.setObjectName('gamma') + + self.setColumnCount(2) + self.setRowCount(1) + + self.setItem(0, 0, QTableWidgetItem('gamma')) + self.setCellWidget(0, 1, self.gamma_spinbox) + self.signal_connect() + + +class RotateAnyTabelWidget(TableWidget): + def __init__(self, parent=None): + super(RotateAnyTabelWidget, self).__init__(parent=parent) + self.angle_spinBox = QSpinBox() + self.angle_spinBox.setMinimum(0) + self.angle_spinBox.setSingleStep(1) + self.angle_spinBox.setMaximum(360) + self.angle_spinBox.setObjectName('angle') + + self.setColumnCount(2) + self.setRowCount(1) + self.setItem(0, 0, QTableWidgetItem('旋转角度')) + self.setCellWidget(0, 1, self.angle_spinBox) + self.signal_connect() + + +class ExposureTabelWidget(TableWidget): + def __init__(self, parent=None): + super(ExposureTabelWidget, self).__init__(parent=parent) + + self.alpha_spinBox = QDoubleSpinBox() + self.alpha_spinBox.setMinimum(0) + self.alpha_spinBox.setMaximum(3) + self.alpha_spinBox.setSingleStep(0.1) + self.alpha_spinBox.setObjectName('alpha') + + self.setColumnCount(2) + self.setRowCount(1) + + self.setItem(0, 0, QTableWidgetItem('曝光度')) + self.setCellWidget(0, 1, self.alpha_spinBox) + self.signal_connect() + + +class ContrastTabelWidget(TableWidget): + def __init__(self, parent=None): + super(ContrastTabelWidget, self).__init__(parent=parent) + + self.alpha_spinBox = QDoubleSpinBox() + self.alpha_spinBox.setMinimum(0) + self.alpha_spinBox.setSingleStep(0.1) + self.alpha_spinBox.setObjectName('alpha') + + self.setColumnCount(2) + self.setRowCount(1) + + self.setItem(0, 0, QTableWidgetItem('对比度')) + self.setCellWidget(0, 1, self.alpha_spinBox) + self.signal_connect() + + +class ColorTemperatureTabelWidget(TableWidget): + def __init__(self, parent=None): + super(ColorTemperatureTabelWidget, self).__init__(parent=parent) + self.alpha_spinBox = QSpinBox() + self.alpha_spinBox.setRange(-200, 200) + self.alpha_spinBox.setSingleStep(1) + self.alpha_spinBox.setObjectName('n') + + self.setColumnCount(2) + self.setRowCount(1) + self.setItem(0, 0, QTableWidgetItem('色温')) + self.setCellWidget(0, 1, self.alpha_spinBox) + self.signal_connect() + + +class HueTabelWidget(TableWidget): + def __init__(self, parent=None): + super(HueTabelWidget, self).__init__(parent=parent) + self.alpha_spinBox = QSpinBox() + self.alpha_spinBox.setRange(-200, 200) + self.alpha_spinBox.setSingleStep(1) + self.alpha_spinBox.setObjectName('n') + + self.setColumnCount(2) + self.setRowCount(1) + self.setItem(0, 0, QTableWidgetItem('色调')) + self.setCellWidget(0, 1, self.alpha_spinBox) + self.signal_connect() + + +class SaturationTabelWidget(TableWidget): + def __init__(self, parent=None): + super(SaturationTabelWidget, self).__init__(parent=parent) + self.angle_spinBox = QSpinBox() + self.angle_spinBox.setRange(-50, 50) + self.angle_spinBox.setSingleStep(1) + self.angle_spinBox.setObjectName('x') + + self.setColumnCount(2) + self.setRowCount(1) + self.setItem(0, 0, QTableWidgetItem('饱和度')) + self.setCellWidget(0, 1, self.angle_spinBox) + self.signal_connect() + + +class PixelateTabelWidget(TableWidget): + def __init__(self, parent=None): + super(PixelateTabelWidget, self).__init__(parent=parent) + self.size_spinBox = QSpinBox() + self.size_spinBox.setRange(1, 1000) + self.size_spinBox.setSingleStep(10) + self.size_spinBox.setObjectName('size') + + self.setColumnCount(2) + self.setRowCount(1) + self.setItem(0, 0, QTableWidgetItem('像素大小')) + self.setCellWidget(0, 1, self.size_spinBox) + self.signal_connect() + + +class BlurTabelWidget(TableWidget): + def __init__(self, parent=None): + super(BlurTabelWidget, self).__init__(parent=parent) + self.size_spinBox = QSpinBox() + self.size_spinBox.setRange(1, 100) + self.size_spinBox.setSingleStep(1) + self.size_spinBox.setObjectName('size') + + self.setColumnCount(2) + self.setRowCount(1) + self.setItem(0, 0, QTableWidgetItem('模糊大小')) + self.setCellWidget(0, 1, self.size_spinBox) + self.signal_connect() + + +class HSLRedWidget(TableWidget): + def __init__(self, parent=None): + super(HSLRedWidget, self).__init__(parent=parent) + self.red_param_s_spinBox = QDoubleSpinBox() + self.red_param_s_spinBox.setMinimum(0) + self.red_param_s_spinBox.setSingleStep(0.01) + self.red_param_s_spinBox.setMaximum(2) + self.red_param_s_spinBox.setObjectName('red_param_s') + + self.red_param_v_spinBox = QDoubleSpinBox() + self.red_param_v_spinBox.setMinimum(0) + self.red_param_v_spinBox.setSingleStep(0.01) + self.red_param_v_spinBox.setMaximum(2) + self.red_param_v_spinBox.setObjectName('red_param_v') + + self.setColumnCount(2) + self.setRowCount(2) + self.setItem(0, 0, QTableWidgetItem('红色饱和度')) + self.setCellWidget(0, 1, self.red_param_v_spinBox) + self.setItem(1, 0, QTableWidgetItem('红色亮度')) + self.setCellWidget(1, 1, self.red_param_s_spinBox) + self.signal_connect() + + +class HSLOrangeWidget(TableWidget): + def __init__(self, parent=None): + super(HSLOrangeWidget, self).__init__(parent=parent) + self.orange_param_s_spinBox = QDoubleSpinBox() + self.orange_param_s_spinBox.setMinimum(0) + self.orange_param_s_spinBox.setSingleStep(0.01) + self.orange_param_s_spinBox.setMaximum(2) + self.orange_param_s_spinBox.setObjectName('orange_param_s') + + self.orange_param_v_spinBox = QDoubleSpinBox() + self.orange_param_v_spinBox.setMinimum(0) + self.orange_param_v_spinBox.setSingleStep(0.01) + self.orange_param_v_spinBox.setMaximum(2) + self.orange_param_v_spinBox.setObjectName('orange_param_v') + + self.setColumnCount(2) + self.setRowCount(2) + self.setItem(0, 0, QTableWidgetItem('橙色饱和度')) + self.setCellWidget(0, 1, self.orange_param_v_spinBox) + self.setItem(1, 0, QTableWidgetItem('橙色亮度')) + self.setCellWidget(1, 1, self.orange_param_s_spinBox) + self.signal_connect() + + +class HSLYellowWidget(TableWidget): + def __init__(self, parent=None): + super(HSLYellowWidget, self).__init__(parent=parent) + self.yellow_param_s_spinBox = QDoubleSpinBox() + self.yellow_param_s_spinBox.setMinimum(0) + self.yellow_param_s_spinBox.setSingleStep(0.01) + self.yellow_param_s_spinBox.setMaximum(2) + self.yellow_param_s_spinBox.setObjectName('yellow_param_s') + + self.yellow_param_v_spinBox = QDoubleSpinBox() + self.yellow_param_v_spinBox.setMinimum(0) + self.yellow_param_v_spinBox.setSingleStep(0.01) + self.yellow_param_v_spinBox.setMaximum(2) + self.yellow_param_v_spinBox.setObjectName('yellow_param_v') + + self.setColumnCount(2) + self.setRowCount(2) + self.setItem(0, 0, QTableWidgetItem('黄色饱和度')) + self.setCellWidget(0, 1, self.yellow_param_v_spinBox) + self.setItem(1, 0, QTableWidgetItem('黄色亮度')) + self.setCellWidget(1, 1, self.yellow_param_s_spinBox) + self.signal_connect() + + +class HSLGreenWidget(TableWidget): + def __init__(self, parent=None): + super(HSLGreenWidget, self).__init__(parent=parent) + self.green_param_s_spinBox = QDoubleSpinBox() + self.green_param_s_spinBox.setMinimum(0) + self.green_param_s_spinBox.setSingleStep(0.01) + self.green_param_s_spinBox.setMaximum(2) + self.green_param_s_spinBox.setObjectName('green_param_s') + + self.green_param_v_spinBox = QDoubleSpinBox() + self.green_param_v_spinBox.setMinimum(0) + self.green_param_v_spinBox.setSingleStep(0.01) + self.green_param_v_spinBox.setMaximum(2) + self.green_param_v_spinBox.setObjectName('green_param_v') + + self.setColumnCount(2) + self.setRowCount(2) + self.setItem(0, 0, QTableWidgetItem('绿色饱和度')) + self.setCellWidget(0, 1, self.green_param_v_spinBox) + self.setItem(1, 0, QTableWidgetItem('绿色亮度')) + self.setCellWidget(1, 1, self.green_param_s_spinBox) + self.signal_connect() + + +class HSLCyanWidget(TableWidget): + def __init__(self, parent=None): + super(HSLCyanWidget, self).__init__(parent=parent) + self.cyan_param_s_spinBox = QDoubleSpinBox() + self.cyan_param_s_spinBox.setMinimum(0) + self.cyan_param_s_spinBox.setSingleStep(0.01) + self.cyan_param_s_spinBox.setMaximum(2) + self.cyan_param_s_spinBox.setObjectName('cyan_param_s') + + self.cyan_param_v_spinBox = QDoubleSpinBox() + self.cyan_param_v_spinBox.setMinimum(0) + self.cyan_param_v_spinBox.setSingleStep(0.01) + self.cyan_param_v_spinBox.setMaximum(2) + self.cyan_param_v_spinBox.setObjectName('cyan_param_v') + + self.setColumnCount(2) + self.setRowCount(2) + self.setItem(0, 0, QTableWidgetItem('青色饱和度')) + self.setCellWidget(0, 1, self.cyan_param_v_spinBox) + self.setItem(1, 0, QTableWidgetItem('青色亮度')) + self.setCellWidget(1, 1, self.cyan_param_s_spinBox) + self.signal_connect() + + +class HSLBlueWidget(TableWidget): + def __init__(self, parent=None): + super(HSLBlueWidget, self).__init__(parent=parent) + self.blue_param_s_spinBox = QDoubleSpinBox() + self.blue_param_s_spinBox.setMinimum(0) + self.blue_param_s_spinBox.setSingleStep(0.01) + self.blue_param_s_spinBox.setMaximum(2) + self.blue_param_s_spinBox.setObjectName('blue_param_s') + + self.blue_param_v_spinBox = QDoubleSpinBox() + self.blue_param_v_spinBox.setMinimum(0) + self.blue_param_v_spinBox.setSingleStep(0.01) + self.blue_param_v_spinBox.setMaximum(2) + self.blue_param_v_spinBox.setObjectName('blue_param_v') + + self.setColumnCount(2) + self.setRowCount(2) + self.setItem(0, 0, QTableWidgetItem('蓝色饱和度')) + self.setCellWidget(0, 1, self.blue_param_v_spinBox) + self.setItem(1, 0, QTableWidgetItem('蓝色亮度')) + self.setCellWidget(1, 1, self.blue_param_s_spinBox) + self.signal_connect() + + +class HSLPurpleWidget(TableWidget): + def __init__(self, parent=None): + super(HSLPurpleWidget, self).__init__(parent=parent) + self.purple_param_s_spinBox = QDoubleSpinBox() + self.purple_param_s_spinBox.setMinimum(0) + self.purple_param_s_spinBox.setSingleStep(0.01) + self.purple_param_s_spinBox.setMaximum(2) + self.purple_param_s_spinBox.setObjectName('purple_param_s') + + self.purple_param_v_spinBox = QDoubleSpinBox() + self.purple_param_v_spinBox.setMinimum(0) + self.purple_param_v_spinBox.setSingleStep(0.01) + self.purple_param_v_spinBox.setMaximum(2) + self.purple_param_v_spinBox.setObjectName('purple_param_v') + + self.setColumnCount(2) + self.setRowCount(2) + self.setItem(0, 0, QTableWidgetItem('紫色饱和度')) + self.setCellWidget(0, 1, self.purple_param_v_spinBox) + self.setItem(1, 0, QTableWidgetItem('紫色亮度')) + self.setCellWidget(1, 1, self.purple_param_s_spinBox) + self.signal_connect() + + +class StyleTransformTableWidget(TableWidget): + def __init__(self, parent=None): + super(StyleTransformTableWidget, self).__init__(parent=parent) + + +class RotateLeftTableWidget(TableWidget): + def __init__(self, parent=None): + super(RotateLeftTableWidget, self).__init__(parent=parent) + + +class RotateRightTableWidget(TableWidget): + def __init__(self, parent=None): + super(RotateRightTableWidget, self).__init__(parent=parent) + + +class UpDownTableWidget(TableWidget): + def __init__(self, parent=None): + super(UpDownTableWidget, self).__init__(parent=parent) \ No newline at end of file diff --git a/custom/treeView.py b/custom/treeView.py new file mode 100644 index 0000000..52c31f1 --- /dev/null +++ b/custom/treeView.py @@ -0,0 +1,35 @@ +import cv2 +import numpy as np +from PyQt5.QtWidgets import * +from PyQt5.QtCore import * + + +class FileSystemTreeView(QTreeView, QDockWidget): + def __init__(self, parent=None): + super().__init__(parent=parent) + self.mainwindow = parent + self.fileSystemModel = QFileSystemModel() + self.fileSystemModel.setRootPath('.') + self.setModel(self.fileSystemModel) + # 隐藏size,date等列 + self.setColumnWidth(0, 200) + self.setColumnHidden(1, True) + self.setColumnHidden(2, True) + self.setColumnHidden(3, True) + # 不显示标题栏 + self.header().hide() + # 设置动画 + self.setAnimated(True) + # 选中不显示虚线 + self.setFocusPolicy(Qt.NoFocus) + self.doubleClicked.connect(self.select_image) + self.setMinimumWidth(200) + + def select_image(self, file_index): + file_name = self.fileSystemModel.filePath(file_index) + if file_name.endswith(('.jpg', '.png', '.bmp')): + src_img = cv2.imdecode(np.fromfile(file_name, dtype=np.uint8), -1) + self.mainwindow.change_image(src_img) + + + diff --git a/custom/treeWidgets.py b/custom/treeWidgets.py new file mode 100644 index 0000000..d5ac2e6 --- /dev/null +++ b/custom/treeWidgets.py @@ -0,0 +1,74 @@ +from PyQt5.QtGui import * +from PyQt5.QtCore import * +from PyQt5.QtWidgets import * + +from config import items + + +class MyTreeWidget(QTreeWidget): + def __init__(self, parent=None): + super().__init__(parent=parent) + self.mainwindow = parent + self.setDragEnabled(True) + # 选中不显示虚线 + # self.setEditTriggers(QAbstractItemView.NoEditTriggers) + self.setFocusPolicy(Qt.NoFocus) + + +class FuncTreeWidget(QTreeWidget): + def __init__(self, parent=None): + super(FuncTreeWidget, self).__init__(parent) + + self.mainwindow = parent + # 根节点 + root1 = QTreeWidgetItem(self) + root1.setText(0, '重构') # 0代表第一列,即Key列 + root1.setIcon(0, QIcon('icons/color.png')) # 为节点设置图标 + self.setColumnWidth(0, 200) # 第一列列宽设为200 + self.header().hide() + self.itemClicked.connect(self.function) + + # 添加子节点1 + child1 = QTreeWidgetItem(root1) + child1.setText(0, '裁剪') + child1.setIcon(0, QIcon('icons/color.png')) + + root2 = QTreeWidgetItem(self) + root2.setText(0, '调整') # 第一列Key为 子节点1 + root2.setIcon(0, QIcon('icons/color.png')) + + child4 = QTreeWidgetItem(root2) + child4.setText(0, '光效') + child4.setIcon(0, QIcon('icons/color.png')) + + child5 = QTreeWidgetItem(root2) + child5.setText(0, '色彩') + child5.setIcon(0, QIcon('icons/color.png')) + + child6 = QTreeWidgetItem(root2) + child6.setText(0, 'HSL') + child6.setIcon(0, QIcon('icons/color.png')) + + child8 = QTreeWidgetItem(root2) + child8.setText(0, '质感') + child8.setIcon(0, QIcon('icons/color.png')) + + child10 = QTreeWidgetItem(root2) + child10.setText(0, '特效') + child10.setIcon(0, QIcon('icons/color.png')) + + root3 = QTreeWidgetItem(self) + root3.setText(0, '风格迁移') + root3.setIcon(0, QIcon('icons/color.png')) + + root4 = QTreeWidgetItem(self) + root4.setText(0, '其他操作') + root4.setIcon(0, QIcon('icons/color.png')) + + # 默认所有节点都处于展开状态 + # self.expandAll() + + def function(self): + func_item = self.currentItem() + self.mainwindow.update_dock(func_item.text(0)) + diff --git a/flags.py b/flags.py new file mode 100644 index 0000000..fbd4a70 --- /dev/null +++ b/flags.py @@ -0,0 +1,96 @@ +import cv2 + +GRAYING_STACKED_WIDGET = 0 +FILTER_STACKED_WIDGET = 1 +MORPH_STACKED_WIDGET = 2 +GRAD_STACKED_WIDGET = 3 +THRESH_STACKED_WIDGET = 4 +EDGE_STACKED_WIDGET = 5 + +BGR2GRAY_COLOR = 0 +GRAY2BGR_COLOR = 1 +COLOR = { + BGR2GRAY_COLOR: cv2.COLOR_BGR2GRAY, + GRAY2BGR_COLOR: cv2.COLOR_GRAY2BGR +} + +MEAN_FILTER = 0 +GAUSSIAN_FILTER = 1 +MEDIAN_FILTER = 2 + +ERODE_MORPH_OP = 0 +DILATE_MORPH_OP = 1 +OPEN_MORPH_OP = 2 +CLOSE_MORPH_OP = 3 +GRADIENT_MORPH_OP = 4 +TOPHAT_MORPH_OP = 5 +BLACKHAT_MORPH_OP = 6 + +MORPH_OP = { + ERODE_MORPH_OP: cv2.MORPH_ERODE, + DILATE_MORPH_OP: cv2.MORPH_DILATE, + OPEN_MORPH_OP: cv2.MORPH_OPEN, + CLOSE_MORPH_OP: cv2.MORPH_CLOSE, + GRADIENT_MORPH_OP: cv2.MORPH_GRADIENT, + TOPHAT_MORPH_OP: cv2.MORPH_TOPHAT, + BLACKHAT_MORPH_OP: cv2.MORPH_BLACKHAT +} + +RECT_MORPH_SHAPE = 0 +CROSS_MORPH_SHAPE = 1 +ELLIPSE_MORPH_SHAPE = 2 + +MORPH_SHAPE = { + RECT_MORPH_SHAPE: cv2.MORPH_RECT, + CROSS_MORPH_SHAPE: cv2.MORPH_CROSS, + ELLIPSE_MORPH_SHAPE: cv2.MORPH_ELLIPSE +} + +SOBEL_GRAD = 0 +SCHARR_GRAD = 1 +LAPLACIAN_GRAD = 2 + +BINARY_THRESH_METHOD = 0 +BINARY_INV_THRESH_METHOD = 1 +TRUNC_THRESH_METHOD = 2 +TOZERO_THRESH_METHOD = 3 +TOZERO_INV_THRESH_METHOD = 4 +OTSU_THRESH_METHOD = 5 +THRESH_METHOD = { + BINARY_THRESH_METHOD: cv2.THRESH_BINARY, # 0 + BINARY_INV_THRESH_METHOD: cv2.THRESH_BINARY_INV, # 1 + TRUNC_THRESH_METHOD: cv2.THRESH_TRUNC, # 2 + TOZERO_THRESH_METHOD: cv2.THRESH_TOZERO, # 3 + TOZERO_INV_THRESH_METHOD: cv2.THRESH_TOZERO_INV, # 4 + OTSU_THRESH_METHOD: cv2.THRESH_OTSU # 5 +} + +EXTERNAL_CONTOUR_MODE = 0 +LIST_CONTOUR_MODE = 1 +CCOMP_CONTOUR_MODE = 2 +TREE_CONTOUR_MODE = 3 +CONTOUR_MODE = { + EXTERNAL_CONTOUR_MODE: cv2.RETR_EXTERNAL, + LIST_CONTOUR_MODE: cv2.RETR_LIST, + CCOMP_CONTOUR_MODE: cv2.RETR_CCOMP, + TREE_CONTOUR_MODE: cv2.RETR_TREE +} + +NONE_CONTOUR_METHOD = 0 +SIMPLE_CONTOUR_METHOD = 1 +CONTOUR_METHOD = { + NONE_CONTOUR_METHOD: cv2.CHAIN_APPROX_NONE, + SIMPLE_CONTOUR_METHOD: cv2.CHAIN_APPROX_SIMPLE +} + +NORMAL_CONTOUR = 0 +RECT_CONTOUR = 1 +MINRECT_CONTOUR = 2 +MINCIRCLE_CONTOUR = 3 + + +# 均衡化 +BLUE_CHANNEL = 0 +GREEN_CHANNEL = 1 +RED_CHANNEL = 2 +ALL_CHANNEL = 3 diff --git a/icons/branch-close.png b/icons/branch-close.png new file mode 100644 index 0000000..1a54719 Binary files /dev/null and b/icons/branch-close.png differ diff --git a/icons/branch-open.png b/icons/branch-open.png new file mode 100644 index 0000000..5b733fd Binary files /dev/null and b/icons/branch-open.png differ diff --git a/icons/color.png b/icons/color.png new file mode 100644 index 0000000..e6be09f Binary files /dev/null and b/icons/color.png differ diff --git a/icons/main.png b/icons/main.png new file mode 100644 index 0000000..c0dbddd Binary files /dev/null and b/icons/main.png differ diff --git a/icons/右旋转.png b/icons/右旋转.png new file mode 100644 index 0000000..e845a3e Binary files /dev/null and b/icons/右旋转.png differ diff --git a/icons/左旋转.png b/icons/左旋转.png new file mode 100644 index 0000000..4cac983 Binary files /dev/null and b/icons/左旋转.png differ diff --git a/icons/直方图.png b/icons/直方图.png new file mode 100644 index 0000000..81e507d Binary files /dev/null and b/icons/直方图.png differ diff --git a/style/candy.t7 b/style/candy.t7 new file mode 100644 index 0000000..69e37b1 Binary files /dev/null and b/style/candy.t7 differ diff --git a/style/composition_vii.t7 b/style/composition_vii.t7 new file mode 100644 index 0000000..0201669 Binary files /dev/null and b/style/composition_vii.t7 differ diff --git a/style/feathers.t7 b/style/feathers.t7 new file mode 100644 index 0000000..69c192d Binary files /dev/null and b/style/feathers.t7 differ diff --git a/style/la_muse.t7 b/style/la_muse.t7 new file mode 100644 index 0000000..b8176a7 Binary files /dev/null and b/style/la_muse.t7 differ diff --git a/style/mosaic.t7 b/style/mosaic.t7 new file mode 100644 index 0000000..44aa0a1 Binary files /dev/null and b/style/mosaic.t7 differ diff --git a/style/starry_night.t7 b/style/starry_night.t7 new file mode 100644 index 0000000..78a8e78 Binary files /dev/null and b/style/starry_night.t7 differ diff --git a/style/the_scream.t7 b/style/the_scream.t7 new file mode 100644 index 0000000..f5e5736 Binary files /dev/null and b/style/the_scream.t7 differ diff --git a/style/the_wave.t7 b/style/the_wave.t7 new file mode 100644 index 0000000..73af44b Binary files /dev/null and b/style/the_wave.t7 differ diff --git a/style/udnie.t7 b/style/udnie.t7 new file mode 100644 index 0000000..6249ef3 Binary files /dev/null and b/style/udnie.t7 differ diff --git a/tmp.jpg b/tmp.jpg new file mode 100644 index 0000000..fbec5e5 Binary files /dev/null and b/tmp.jpg differ