from PyQt5.QtGui import QMouseEvent, QPixmap, QImage, QPainter, QPen, QColor
from PyQt5.QtWidgets import (
QApplication,
QWidget,
QPushButton,
QLabel,
QVBoxLayout,
QHBoxLayout,
QFileDialog,
QLineEdit,
QRadioButton,
QMessageBox,
QInputDialog,
)
from PIL import Image, ImageEnhance, ImageColor
from PyQt5.QtCore import Qt, QPoint, QRect
from PyQt5.QtGui import QPixmap, QPainter, QFont
from PyQt5 import QtGui
import os
import sys
import cv2
import math
class mainwindow(QWidget):
def __init__(self):
super().__init__()
self.top = 200
self.left = 500
self.width = 700
self.height = 700
self.imageheight = 600
self.imagewidth = 600
self.setWindowTitle("face tagging")
self.setGeometry(self.left, self.top, self.width, self.height)
self.label = QLabel("image presented here ", self)
self.label.move(200, 200)
self.btn2 = QPushButton("image editor", self)
self.btn2.clicked.connect(self.editing_window)
self.btn3 = QPushButton("Locate face", self)
self.btn3.clicked.connect(self.findFace)
self.btn4 = QPushButton("delete faces", self)
self.btn4.clicked.connect(self.delete_false_face)
self.btn5 = QPushButton("add faces", self)
self.btn6 = QPushButton("name tag", self)
self.btn6.clicked.connect(self.createtagwindow)
self.btn5.clicked.connect(self.enabled)
self.imagepath = ""
self.fList = facelist()
self.delclick = False
self.enable = False
# QPixmap to draw on
self.pix = QtGui.QPixmap(self.imagepath)
self.begin = QPoint()
self.destination = QPoint()
vbox = QHBoxLayout()
vbox.addWidget(self.btn2)
vbox.addWidget(self.btn3)
vbox.addWidget(self.btn4)
vbox.addWidget(self.btn5)
buttons_widget = QWidget()
buttons_widget.setLayout(vbox)
hbox = QHBoxLayout()
hbox.addWidget(self.label)
hbox.addWidget(buttons_widget)
self.setLayout(hbox)
self.setwidget()
def setwidget(self):
self.btn1 = QPushButton("upload here", self)
self.btn1.clicked.connect(self.obtainphoto)
def editing_window(self):
self.editwin = createwindow(self)
self.editwin.show()
def obtainphoto(self):
fname = QFileDialog.getOpenFileName(self, "open file")
self.imagepath = fname[0]
self.originalpath = fname[0]
self.renderimage()
def renderimage(self):
self.pixmap = QPixmap(self.imagepath)
self.pixmap_resized = self.pixmap.scaled(
self.imagewidth,
self.imageheight,
Qt.KeepAspectRatio,
Qt.SmoothTransformation,
)
self.label.setPixmap(self.pixmap_resized)
self.pix = QtGui.QPixmap(self.pixmap_resized)
def display_image(self, img):
height, width, colors = img.shape
bytesperline = 3 * width
image = QImage(img.data, width, height, bytesperline, QImage.Format_RGB888)
self.image = image.rgbSwapped()
self.label.setPixmap(QPixmap.fromImage(self.image))
def findFace(self):
face_cascade = cv2.CascadeClassifier("haarcascade_frontalface_default.xml")
img = cv2.imread(self.imagepath, cv2.IMREAD_COLOR)
img = cv2.resize(img, (self.imagewidth, self.imageheight))
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
faces = face_cascade.detectMultiScale(gray, 2, 1).tolist()
for x, y, w, h in faces:
self.fList.append_face(x, y, w, h)
cv2.rectangle(img, (x, y), (x + w, y + h), (255, 255, 0), 2)
self.display_image(img)
def createtagwindow(self):
self.tagwin = tagwindow()
self.tagwin.setwidgets(self)
self.tagwin.show()
def delete_false_face(self):
if self.label.pixmap() is None:
print("Photo is not present within the given area")
elif self.fList is None or self.fList.count_face() == 0:
print("No face is detected")
else:
print("Which face do you want to delete?")
self.delclick = True
def createaddfacewin(self):
self.addfacewin = addfacewindow(self)
self.addfacewin.setwidgets(self)
self.addfacewin.show()
def mousePressEvent(self, event):
if event.buttons() & Qt.LeftButton and self.enable:
self.begin = event.pos()
self.destination = self.begin
self.update()
def mouseMoveEvent(self, event):
if event.buttons() & Qt.LeftButton and self.enable:
self.destination = event.pos()
self.update()
def mouseReleaseEvent(self, event):
if event.button() & Qt.LeftButton and self.enable:
rect = self.get_rect_from_center(self.begin, self.destination)
painter = QPainter(self.pix)
painter.setPen(QPen(QColor("blue"), 3))
painter.drawRect(rect.normalized())
self.fList.append_face(rect.x(), rect.y(), rect.width(), rect.height())
self.begin, self.destination = QPoint(), QPoint()
self.update()
def paintEvent(self, event):
painter = QPainter(self)
if self.pix:
painter.drawPixmap(0, 0, self.pix)
if not self.begin.isNull() and not self.destination.isNull() and self.enable:
painter.setPen(QPen(QColor("blue"), 3))
rect = self.get_rect_from_center(self.begin, self.destination)
painter.drawRect(rect.normalized())
def get_rect_from_center(self, center, edge):
width = abs(edge.x() - center.x()) * 2
height = abs(edge.y() - center.y()) * 2
top_left = QPoint(center.x() - width // 2, center.y() - height // 2)
bottom_right = QPoint(center.x() + width // 2, center.y() + height // 2)
return QRect(top_left, bottom_right)
def enabled(self):
self.enable = True
class createwindow(QWidget):
def __init__(self, mainwindow_instance):
super().__init__()
self.mainwindow_instance = mainwindow_instance
self.width = 350
self.height = 350
self.setWindowTitle("Image Editor")
self.setGeometry(500, 200, self.width, self.height)
self.setwidget()
def setwidget(self):
self.labelwidth = QLabel("width editor", self)
self.labelwidth.move(20, 20)
self.textwidth = QLineEdit("width", self)
self.textwidth.move(20, 50)
self.labelheight = QLabel("height editor", self)
self.labelheight.move(20, 100)
self.textheight = QLineEdit("height", self)
self.textheight.move(20, 130)
self.labelcolor = QLabel("adjust photo color", self)
self.labelcolor.move(20, 180)
self.radiobtn1 = QRadioButton("original", self)
self.radiobtn1.setChecked(True)
self.radiobtn1.move(20, 210)
self.radiochecked = "original"
self.radiobtn2 = QRadioButton("grey", self)
self.radiobtn2.move(20, 240)
self.radiobtn3 = QRadioButton("red", self)
self.radiobtn3.move(20, 270)
self.radiobtn4 = QRadioButton("green", self)
self.radiobtn4.move(20, 300)
self.radiobtn5 = QRadioButton("blue", self)
self.radiobtn5.move(20, 330)
self.radiobtn6 = QRadioButton("turquoise", self)
self.radiobtn6.move(90, 210)
self.radiobtn7 = QRadioButton("orange", self)
self.radiobtn7.move(90, 240)
self.btn_confirm = QPushButton("confirm changes", self)
self.btn_confirm.move(230, 20)
self.btn_confirm.clicked.connect(self.editimage)
self.radiobtn1.toggled.connect(self.btnstate)
self.radiobtn2.toggled.connect(self.btnstate)
self.radiobtn3.toggled.connect(self.btnstate)
self.radiobtn4.toggled.connect(self.btnstate)
self.radiobtn5.toggled.connect(self.btnstate)
self.radiobtn6.toggled.connect(self.btnstate)
self.radiobtn7.toggled.connect(self.btnstate)
def btnstate(self):
radiobtn = self.sender()
self.radiochecked = radiobtn.text()
def editimage(self):
img = Image.open(self.mainwindow_instance.originalpath)
img = img.convert("RGB")
if self.radiochecked == "original":
img_edited = img
elif self.radiochecked == "grey":
img_edited = img.convert("L")
elif self.radiochecked == "red":
red = (
0.90,
0.36,
0.18,
0.00,
0.11,
0.72,
0.07,
0.00,
0.02,
0.12,
0.95,
0.00,
)
img_edited = img.convert("RGB", red)
elif self.radiochecked == "blue":
blue = (
0.18,
0.36,
0.90,
0.00,
0.07,
0.72,
0.11,
0.00,
0.95,
0.12,
0.02,
0.00,
)
img_edited = img.convert("RGB", blue)
elif self.radiochecked == "green":
green = (
0.18,
0.90,
0.36,
0.00,
0.07,
0.11,
0.72,
0.00,
0.95,
0.02,
0.12,
0.00,
)
img_edited = img.convert("RGB", green)
elif self.radiochecked == "turquoise":
turquoise = (
0.18,
0.36,
0.90,
0.00,
0.72,
0.11,
0.07,
0.00,
0.12,
0.02,
0.95,
0.00,
)
img_edited = img.convert("RGB", turquoise)
elif self.radiochecked == "orange":
orange = (
0.95,
0.02,
0.12,
0.00,
0.11,
0.72,
0.07,
0.00,
0.18,
0.36,
0.90,
0.00,
)
img_edited = img.convert("RGB", orange)
if img_edited.mode == "RGBA":
img_edited = img_edited.convert("RGB")
img_edited.save("image_edited.jpg", "JPEG")
self.mainwindow_instance.imagepath = os.path.join(
os.getcwd(), "image_edited.jpg"
)
try:
imgwidth_edited = self.textwidth.text()
imgheight_edited = self.textheight.text()
if imgwidth_edited == "width":
imgwidth_edited = str(self.mainwindow_instance.imagewidth)
if imgheight_edited == "height":
imgheight_edited = str(self.mainwindow_instance.imageheight)
self.mainwindow_instance.imagewidth = int(imgwidth_edited)
self.mainwindow_instance.imageheight = int(imgheight_edited)
self.mainwindow_instance.renderimage()
self.close()
except ValueError:
QMessageBox.warning(
self,
"Invalid Input",
"Please enter valid integer values for width and height.",
)
class addfacewindow(QWidget):
def __init__(self, mainwindow):
super().__init__()
def setwidgets(self, mainwindow):
self.setGeometry(mainwindow.left, mainwindow.top, 200, 300)
self.mlabel = squarelabel(
mainwindow.imagepath,
mainwindow.imagewidth,
mainwindow.imageheight,
mainwindow.fList,
)
self.pixmap = QPixmap(mainwindow.imagepath)
self.pixmap_resized = self.pixmap.scaled(
mainwindow.imagewidth, mainwindow.imageheight
)
self.mlabel.setPixmap(self.pixmap_resized)
self.addface = QPushButton("add face", self)
self.addface.clicked.connect(lambda: self.mlabel.addface())
self.btnconfirm = QPushButton("confirm", self)
vbox = QVBoxLayout()
vbox.addWidget(self.addface)
vbox.addWidget(self.btnconfirm)
widgetbutton = QWidget()
widgetbutton.setLayout(vbox)
hbox = QHBoxLayout()
hbox.addWidget(self.mlabel)
hbox.addWidget(widgetbutton)
self.setLayout(hbox)
class tagwindow(mainwindow):
def __init__(self):
super().__init__()
def setwidgets(self, mainwindow):
self.setGeometry(self.left, self.top, 200, 300)
self.mlabel = taglabel(
mainwindow.imagepath, mainwindow.width, mainwindow.height, mainwindow.fList
)
self.btnSave = QPushButton("store this", self)
self.btnSave.clicked.connect(lambda: self.mlabel.saveFile())
self.btnOK = QPushButton("confirm", self)
self.btnOK.clicked.connect(lambda: self.finishTag(mainwindow))
vbox = QVBoxLayout()
vbox.addWidget(self.btnSave)
vbox.addWidget(self.btnOK)
button_widget = QWidget()
button_widget.setLayout(vbox)
hbox = QHBoxLayout()
hbox.addWidget(self.mlabel)
hbox.addWidget(button_widget)
self.setLayout(hbox)
class squarelabel(QLabel):
def __init__(self, imgpath, w, h, facelist):
super().__init__()
self.pixmap = QPixmap(imgpath)
self.pixmap_resized = self.pixmap.scaled(w, h)
self.setPixmap(self.pixmap_resized)
painter = QPainter(self.pixmap_resized)
painter.setPen(QPen(QColor("blue"), 3))
self.facelist = facelist
for f in self.facelist.face_list:
print(f.x, f.y, f.w, f.h)
painter.drawRect(f.x, f.y, f.w, f.h)
self.setPixmap(self.pixmap_resized)
self.left_clicking = False
def mousepressevent(self, event):
if event.button() == 1:
self.startX = event.x()
self.starty = event.y()
self.left_clicking = True
def mouserelease(self, event):
if event.button() == 1:
self.finishX = event.x()
self.finishY = event.y()
self.left_clicking = False
def mousemovement(self, event):
if self.left_clicking:
self.pixmap_temp = self.pixmap_resized.copy()
painter = QPainter(self.pixmap_temp)
painter.setPen(QPen(QColor("green"), 3))
painter.drawRect(
self.startX,
self.startY,
event.x() - self.startX,
event.y() - self.startY,
)
self.setPixmap(self.pixmap_temp)
def addface(self):
x, y, w, h = (
self.startX,
self.startY,
self.finishX - self.startX,
self.finishY - self.startY,
)
self.facelist.append_face(x, y, w, h)
painter = QPainter(self.pixmap_temp)
painter.setPen(QPen(QColor("blue"), 3))
painter.drawRect(x, y, w, h)
self.setPixmap(self.pixmap_resized)
def finishface(self, mainwindow):
mainwindow.label.setPixmap(self.mlabel.pixmap_resized)
self.close()
class taglabel(squarelabel):
def __init__(self, imgpath, w, h, facelist):
super().__init__(imgpath, w, h, facelist)
def mousepress(self, event):
for f in self.facelist.face_list:
if f.x <= event.x() <= f.x + f.w and f.y <= event.y() <= f.y + f.h:
print("face Id", f.id, f.name)
text, pressconfirm = QInputDialog.getText(
self, "input", "name:", QLineEdit.Normal
)
if pressconfirm and text != "":
f.name = text
break
self.drawnames()
def drawnames(self):
self.pixmap_temp = self.pixmap_resized.copy()
painter = QPainter(self.pixmap_temp)
painter.setPen(QPen(QColor("blue"), 3))
for f in self.facelist.face_list:
painter.drawText(f.x, f.y - 5, f.name)
painter.end()
self.setPixmap(self.pixmap_temp)
def saveFile(self):
text, confirmpress = QInputDialog.getText(
self, "file name inputter", "file name", QLineEdit.Normal
)
if confirmpress:
self.pixmap_temp.save(text + "jpg", "JPG")
def finishTag(self, mainwindow):
mainwindow.label.setPixmap(self.mlabel.pixmap_temp)
self.close()
def mouserelease(self, event):
pass
def mousemove(self, event):
pass
class facelist:
def __init__(self):
self.face_list = []
self.face_id = 0
def append_face(self, x, y, w, h, name=None):
face = Face(self.face_id, x, y, w, h, name)
self.face_list.append(face)
self.face_id += 1
def remove_face(self, face_id):
for face in self.face_list:
if face.id == face_id:
self.face_list.remove(face)
break
def count_face(self):
return len(self.face_list)
class Face:
def __init__(self, face_id, x, y, w, h, name=None):
self.id = face_id
self.x = x
self.y = y
self.w = w
self.h = h
self.name = name
if __name__ == '__main__':
app = QApplication(sys.argv)
mainwin = mainwindow()
mainwin.show()
sys.exit(app.exec_())
after pressing the “upload image ” button, i expected a singular image which i could discover, add, and remove faces from. However, what ended up occuring were two overlapping images, with one being able to have the faces removed and the other one being able to have faces added.
Dark blue square denotes how the faces are to be drawn.