here is my simple code to display the image in QGraphicsView in pyqt python 3.7. I want an image pixel when the mouse is pressed on a scene or window of QGraphicsView or QGraphicsScene.
Mouse Press Function
Mouse Press Event Handler
def mousePressEvent(self):
p = QtGui.QCursor.pos()
print("pressed here: ", p)
Mouse Press Event caller
self.scene1.mousePressEvent = mousePressEvent
Main Code
import cv2
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtGui import *
from PyQt5.QtWidgets import QGraphicsScene, QAction
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(800, 600)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.graphicsView = QtWidgets.QGraphicsView(self.centralwidget)
self.graphicsView.setGeometry(QtCore.QRect(20, 10, 761, 561))
self.graphicsView.setObjectName("graphicsView")
MainWindow.setCentralWidget(self.centralwidget)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
# ---- Mouse Press Event Handler ---- #
def mousePressEvent(self):
p = QtGui.QCursor.pos() # Here I want image pixel coordinate (x,y) how we can..?
print("pressed here: ", p)
# ---- Mouse Press Event caller ---- #
self.scene1.mousePressEvent = mousePressEvent
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
# -------------------------------------------------
image = cv2.imread('lena.jpg') # Read image
image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
height, width = image.shape # read image size
self.image_disp = QImage(image.data, width, height, QImage.Format_Grayscale8)
# -------------------------------------------------
self.scene1 = QGraphicsScene()
pixMap = QPixmap.fromImage(self.image_disp)
self.scene1.addPixmap(pixMap)
self.graphicsView.setScene(self.scene1)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
You should not modify the class generated by Qt Designer(1), instead create another class that inherits from a widget and use the initial class as an interface.
Do not override the mousePressEvent method using self.scene1.mousePressEvent = mousePressEvent because you are deleting the default implementation, instead you can create a class that inherits from QGraphicsScene or use an event filter, in this case I will use the second method.
To obtain the position of the mouse with respect to the image (QGraphicsPixmapItem), you must use the transformations between the different elements of the Qt Graphics Framework.
import os
import cv2
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(800, 600)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.graphicsView = QtWidgets.QGraphicsView(self.centralwidget)
self.graphicsView.setGeometry(QtCore.QRect(20, 10, 761, 561))
self.graphicsView.setObjectName("graphicsView")
MainWindow.setCentralWidget(self.centralwidget)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.setupUi(self)
self.scene = QtWidgets.QGraphicsScene(self)
self.graphicsView.setScene(self.scene)
self.scene.installEventFilter(self)
current_dir = os.path.dirname(os.path.realpath(__file__))
filename = os.path.join(current_dir, "lena.jpg")
image = cv2.imread(filename)
image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
height, width = image.shape
image_disp = QtGui.QImage(
image.data, width, height, QtGui.QImage.Format_Grayscale8
)
pixMap = QtGui.QPixmap.fromImage(image_disp)
self.pixmap_item = self.scene.addPixmap(pixMap)
def eventFilter(self, obj, event):
if obj is self.scene and event.type() == QtCore.QEvent.GraphicsSceneMousePress:
spf = event.scenePos()
lpf = self.pixmap_item.mapFromScene(spf)
brf = self.pixmap_item.boundingRect()
if brf.contains(lpf):
lp = lpf.toPoint()
print(lp)
return super().eventFilter(obj, event)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())
(1) Using the Generated Code
Related
I have an application like this 1 with one display to show real-time basler camera into it . I already figured out how to connect to Basler camera and show video on it but the video is not very smooth.
#Connect to a camera
for i in MainWindow.camera_db.all():
if True:
info = None
for x in pylon.TlFactory.GetInstance().EnumerateDevices():
if x.GetSerialNumber() == i['id']:
info = x
break
if info is not None:
camera = pylon.InstantCamera(pylon.TlFactory.GetInstance().CreateDevice(info))
camera.Open()
if MainWindow.viewer1 is None:
MainWindow.viewer1 = BaslerOpenCVViewer(camera)
logging.warning(f'Camera 1 - serial number: {i["id"]}-OK')
else:
logging.warning('Camera with {} serial number not found'.format(i['id']))
and then I tried
def update_frame(self):
try:
frame = MainWindow.viewer1.get_image()
# frame = cv2.imread('test.jpg')
self.load_display1(frame) # take a frame and show it on MainWindow.display
return frame
except Exception as e:
logging.warning(str(e))
self.time_get_image = QtCore.QTimer(self, interval=1)
self.time_get_image.timeout.connect(self.get_image) #call update_frame function every 1ms to get a real-time video from Basler camera but it's not work well
self.time_get_image.start()
Is there another ways to connect to Basler camera continuous mode and show it on application.
create a label and send the img to displayImage fucnbtion. you will get the image.
from pypylon import pylon
import cv2
camera = pylon.InstantCamera(pylon.TlFactory.GetInstance().CreateFirstDevice())
camera.StartGrabbing(pylon.GrabStrategy_LatestImageOnly)
converter = pylon.ImageFormatConverter()
converter.OutputPixelFormat = pylon.PixelType_BGR8packed
converter.OutputBitAlignment = pylon.OutputBitAlignment_MsbAligned
while camera.IsGrabbing():
grabResult = camera.RetrieveResult(5000, pylon.TimeoutHandling_ThrowException)
# if grabResult.GrabSucceded():
image = converter.Convert(grabResult)
img = image.GetArray()
self.displayImage(img)
cv2.imshow("video", img)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cv2.destroyAllWindows()
cv2.waitKey()
def displayImage(self, img):
qformat = QImage.Format_Indexed8
if len(img.shape) == 3:
if (img.shape[2]) == 4:
qformat = QImage.Format_RGB888
else:
qformat = QImage.Format_RGB888
img = QImage(img, img.shape[1], img.shape[0], qformat)
img = img.rgbSwapped()
self.ui.Camera_lbl.setPixmap(QPixmap.fromImage(img))
self.ui.Camera_lbl.setAlignment(QtCore.Qt.AlignHCenter | QtCore.Qt.AlignHCenter)
You can use the following code
from pypylon import pylon
import cv2
# conecting to the first available camera
camera = pylon.InstantCamera(pylon.TlFactory.GetInstance().CreateFirstDevice())
# Grabing Continusely (video) with minimal delay
camera.StartGrabbing(pylon.GrabStrategy_LatestImageOnly)
converter = pylon.ImageFormatConverter()
# converting to opencv bgr format
converter.OutputPixelFormat = pylon.PixelType_BGR8packed
converter.OutputBitAlignment = pylon.OutputBitAlignment_MsbAligned
while camera.IsGrabbing():
grabResult = camera.RetrieveResult(5000, pylon.TimeoutHandling_ThrowException)
if grabResult.GrabSucceeded():
# Access the image data
image = converter.Convert(grabResult)
img = image.GetArray()
cv2.namedWindow('title', cv2.WINDOW_NORMAL)
cv2.imshow('title', img)
k = cv2.waitKey(1)
if k == 27:
break
grabResult.Release()
# Releasing the resource
camera.StopGrabbing()
cv2.destroyAllWindows()
The code is taken from this github:pypylon/samples/opencv.py
I've tried to make a program that uses a scroll, I tried with RecycleView
class TestApp(App):
def build(self):
rc = RecycleView()
box = BoxLayout(orientation="vertical", size_hint_y=None)
b1 = Button(text="1", size_hint_y=None, height=500)
b2 = Button(text="2", size_hint_y=None, height=500)
b3 = Button(text="3", size_hint_y=None, height=500)
box.add_widget(b1)
box.add_widget(b2)
box.add_widget(b3)
box.height = box.minimum_height
rc.add_widget(box)
return rc
if __name__ == '__main__':
TestApp().run()
I was expected that I was able to use the scroll, but the minimum_height seems that is always 0, and I don't want to give the exact height number by hand.
Thank you so much
You have to bind minimum_height to the height using setter as follow:
box.bind(minimum_height=box.setter('height'))
Snippets - py file
def build(self):
rc = RecycleView()
box = BoxLayout(orientation="vertical", size_hint_y=None)
...
box.bind(minimum_height=box.setter('height'))
rc.add_widget(box)
return rc
Output
I'm completely new to opencv and tesseract.
I spent all day trying to make code that would parse game duration from images like that: original image (game duration is in the top left corner)
I came to code that manages to recognize the duration sometimes (about 40% of all cases). Here it is:
try:
from PIL import Image
except ImportError:
import Image
import os
import cv2
import pytesseract
import re
import json
def non_digit_split(s):
return filter(None, re.split(r'(\d+)', s))
def time_to_sec(min, sec):
return (int(min) * 60 + int(sec)).__str__()
def process_img(image_url):
img = cv2.resize(cv2.imread('./images/' + image_url), None, fx=5, fy=5, interpolation=cv2.INTER_CUBIC)
str = pytesseract.image_to_string(img)
if "WIN " in str:
time = list(non_digit_split(str.split("WIN ",1)[1][0:6].strip()))
str = time_to_sec(time[0], time[2])
else:
str = 'Not recognized'
return str
res = {}
img_list = os.listdir('./images')
print(img_list)
for i in img_list:
res[i] = process_img(i)
with open('output.txt', 'w') as file:
file.write(json.dumps(res))
Don't even ask how I came to resizing image, but it helped a little.
I also tried to crop image first like that:
cropped image
but tesseract couldn't find any text here.
I'm sure that the issue I'm trying to solve is pretty easy. Can you please point me the right direction? How should I preprocess it so tesseract will parse it right?
Thanks to #DmitriiZ comment I managed to produce working piece of code.
I made a preprocessor that outputs something like that:
Preprocessed image
Tesseract handles it just fine.
Here is the full code:
try:
from PIL import Image
except ImportError:
import Image
import os
import pytesseract
import json
def is_dark(image):
pixels = image.getdata()
black_thresh = 100
nblack = 0
for pixel in pixels:
if (sum(pixel) / 3) < black_thresh:
nblack += 1
n = len(pixels)
if (nblack / float(n)) > 0.5:
return True
else:
return False
def preprocess(img):
basewidth = 500
wpercent = (basewidth/float(img.size[0]))
hsize = int((float(img.size[1])*float(wpercent)))
#Enlarging image
img = img.resize((basewidth,hsize), Image.ANTIALIAS)
#Converting image to black and white
img = img.convert("1", dither=Image.NONE)
return img
def process_img(image_url):
img = Image.open('./images/' + image_url)
#Area we need to crop can be found in one of two different areas,
#depending on which team won. You can replace that block and is_dark()
#function by just img.crop().
top_area = (287, 15, 332, 32)
crop = img.crop(top_area)
if is_dark(crop):
bot_area = (287, 373, 332, 390)
crop = img.crop(bot_area)
img = preprocess(crop)
str = pytesseract.image_to_string(img)
return str
res = {}
img_list = os.listdir('./images')
print(img_list)
for i in img_list:
res[i] = process_img(i)
with open('output.txt', 'w') as file:
file.write(json.dumps(res))
I have been working on ARDrone long ago. Is there any way to automate the drone based on feet measurements ?
Lets say I have to fly the drone only 6 feet from the ground. How can I do that ?
I do have some rostopics. How to use them to fly the drone only for 6 feet ?
#flyup
rostopic : /cmd_vel geometry_msgs/Twist '{linear: {x: 0.0, y: 0.0, z: 1.0}, angular: {x: 0.0,y: 0.0,z: 0.0}}'
I am using a loop here to implement the same action for couple of times. How can I calibrate it to 6 ft with rostopics ?
Please check the code.
#!/usr/bin/env python
#import library ros
import rospy
import time
from geometry_msgs.msg import Twist
from std_msgs.msg import String
from std_msgs.msg import Empty
from ardrone_autonomy.msg import Navdata
#import class status untuk menentukan status ddari quadcopter
#from drone_status import DroneStatus ` 1`
#COMMAND_PERIOD = 1000
class AutonomousFlight():
def __init__(self):
self.status = ""
rospy.init_node('forward', anonymous=False)
self.rate = rospy.Rate(1)
self.pubTakeoff = rospy.Publisher("ardrone/takeoff",Empty, queue_size=10)
self.pubLand = rospy.Publisher("ardrone/land",Empty, queue_size=10)
self.pubCommand = rospy.Publisher('cmd_vel',Twist, queue_size=10)
self.command = Twist()
#self.commandTimer = rospy.Timer(rospy.Duration(COMMAND_PERIOD/1000.0),self.SendCommand)
self.state_change_time = rospy.Time.now()
rospy.on_shutdown(self.SendLand)
def TakeOff(self):
self.pubTakeoff.publish(Empty())
self.rate.sleep()
def SendLand(self):
self.pubLand.publish(Empty())
def SetCommand(self, linear_x, linear_y, linear_z, angular_x, angular_y, angular_z):
self.command.linear.x = linear_x
self.command.linear.y = linear_y
self.command.linear.z = linear_z
self.command.angular.x = angular_x
self.command.angular.y = angular_y
self.command.angular.z = angular_z
self.pubCommand.publish(self.command)
self.rate.sleep()
if __name__ == '__main__':
try:
i = 0
distance = 0
uav = AutonomousFlight()
while not rospy.is_shutdown():
uav.TakeOff()
if i <=3 :
uav.SetCommand(0,0,1,0,0,0)
i+=1
elif i<=4:
uav.SetCommand(0,0,0,0,0,0)
i+=1
else:
break
uav.SendLand()
except rospy.ROSInterruptException:
pass
From the above code, Drone has just to takeoff and fly upto 6 feet ...how could I do it ?
Regards,
Kathir
Usually when we add a particular widget to a sizer in wxwidgets we specify alignment and border flags as ( .... ,wxALIGN_RIGH | wxLEFT | wxRIGHT , 10 )
My requirement is I would like to have left border of 10 and right border of 20 , how do I achieve this with flag combination or is a way to do it?
I don't think that you can do it the way that you want to.
You would have to omit wx.RIGHT from your command and add an extra dummy widget to the box:
hbox.Add((dummy,-1, wx.LEFT,20))
If attempting to do it in a vertical box:
vbox.Add((-1, 20))
e.g.
#!/usr/bin/python
# -*- coding: utf-8 -*-
# border.py
import wx
class Example(wx.Frame):
def __init__(self, parent, title):
super(Example, self).__init__(parent, title=title,
size=(260, 180))
self.InitUI()
self.Centre()
self.Show()
def InitUI(self):
panel = wx.Panel(self)
panel.SetBackgroundColour('#4f5049')
vbox = wx.BoxSizer(wx.VERTICAL)
hbox = wx.BoxSizer(wx.HORIZONTAL)
midPan = wx.Panel(panel)
midPan.SetBackgroundColour('#ededed')
dummy = wx.StaticText(panel, wx.ID_ANY, "")
midPan2 = wx.Panel(panel)
midPan2.SetBackgroundColour('#1f1f1f')
hbox.Add(midPan, -1, wx.LEFT|wx.TOP, border=10 )
hbox.Add(dummy,-1, wx.LEFT,border=20)
hbox.Add(midPan2, -1, wx.RIGHT, border=10)
vbox.Add(hbox)
panel.SetSizer(vbox)
if __name__ == '__main__':
app = wx.App()
Example(None, title='Border')
app.MainLoop()