Python Forum
Integrating py script onto GUI.
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Integrating py script onto GUI.
#1
Exclamation 
I am a student who is new to Python. For my project, I am tasked to integrate a python program onto my GUI interface at the top left corner of it.

Basically, my program is ran using the CMD terminal with python OSM_extension_FINALIZED.py.

To run my GUI, all I have to do is run this command ./spf.sh and my GUI will appear.

What I am trying to achieve to integrate OSM_extension_FINALIZED.py into the GUI program. Such that the GUI can display a live map of the GPS location trackers at the top left corner as seen in the picture below. As of now, the picture at the top left is only a placeholder.

My GUI code can be viewed here,
#!/usr/bin/env python
#-------------------------------------------------------------------------------
# Camera display using PyQt and PiCamera
# Copyright (c) 2019 Ver 2.0
#-------------------------------------------------------------------------------

VERSION = "SPF_Display v2.00"

import sys, time, threading
from PyQt5 import QtCore
from PyQt5.QtCore import QTimer, QPoint, pyqtSignal, QRect, QSize
from PyQt5.QtWidgets import QApplication, QMainWindow, QTextEdit, QLabel,QPushButton,QMessageBox
from PyQt5.QtWidgets import QWidget, QAction, QVBoxLayout, QHBoxLayout
from PyQt5.QtGui import QFont, QPainter, QImage, QTextCursor, QPixmap, QIcon

from picamera.array import PiRGBArray
from picamera import PiCamera
import Queue as Queue
#-------------------------------------------------------------------------------
# Global Settings
#-------------------------------------------------------------------------------
IMG_SIZE = 640,480          # Fix by the PiCapture SD1 device
TEXT_FONT   = QFont("Courier", 16)

DISP_SCALE  = 1             # Scaling factor for display image
DISP_MSEC   = 50            # Delay between display cycles

image_queue = Queue.Queue() # Queue to hold images
capturing = True            # Flag to indicate capturing
#-------------------------------------------------------------------------------
# Grab images from the camera (separate thread)
#-------------------------------------------------------------------------------
def grab_images(queue):
    camera=PiCamera()
    camera.framerate= 60
    camera.resolution= (IMG_SIZE[0], IMG_SIZE[1])
    rawCapture=PiRGBArray(camera,size=(IMG_SIZE[0], IMG_SIZE[1]))
    time.sleep(0.5)

    try:
        while capturing:
            camera.capture(rawCapture, format='rgb', use_video_port=True)
            image=rawCapture.array
            if image is not None and queue.qsize() < 2:
                queue.put(image)
            else:
                time.sleep(DISP_MSEC / 1000.0)
            rawCapture.truncate(0)
    finally:
        camera.close()
        
#-------------------------------------------------------------------------------
# Image widget
#-------------------------------------------------------------------------------
class ImageWidget(QWidget):
    def __init__(self, parent=None):
        super(ImageWidget, self).__init__(parent)
        self.image = None

    def setImage(self, image):
        self.image = image
        self.setMinimumSize(image.size())
        self.update()

    def paintEvent(self, event):
        qp = QPainter()
        qp.begin(self)
        if self.image:
            qp.drawImage(QPoint(0, 0), self.image)
        qp.end()

#-------------------------------------------------------------------------------       
# Minimap image widget
#-------------------------------------------------------------------------------
class MapWidget(QLabel):
    def __init__(self, parent=None):
        super(MapWidget, self).__init__(parent)
        pixmap = QPixmap('/home/ubuntu/catkin_ws/src/controller/config/map.png')
        self.setMinimumSize(100, 140)
        self.setPixmap(pixmap)
      
#-------------------------------------------------------------------------------
# Main window
#-------------------------------------------------------------------------------
class MyWindow(QMainWindow):
    text_update = pyqtSignal(str)
    
    # Create main window
    def __init__(self, parent=None):
        QMainWindow.__init__(self, parent)

        # Window settings
        self.setWindowTitle(VERSION)
        flags = QtCore.Qt.WindowFlags(QtCore.Qt.FramelessWindowHint | QtCore.Qt.WindowStaysOnTopHint)
        self.setWindowFlags(flags)

        # Widgets settings
        self.central = QWidget(self)
        self.textbox = QTextEdit(self.central)
        self.textbox.setFont(TEXT_FONT)
        self.textbox.setMinimumSize(300, 50)
        self.text_update.connect(self.append_text)
        sys.stdout = self
        print("Image size %u x %u" % IMG_SIZE)
        
        self.mainvlayout = QVBoxLayout()        
        self.vlayout = QVBoxLayout()        # Window layout
        self.displays = QHBoxLayout()
        
        self.dispMap = MapWidget(self)    # Map display
        self.vlayout.addWidget(self.dispMap)  
              
        self.buttonStart = QPushButton(' Start') #Start Button
        self.vlayout.addWidget(self.buttonStart)
        self.buttonStart.clicked.connect(self.startClicked)
        self.buttonStart.show()
        self.buttonStart.setIcon(QIcon(QPixmap('/home/ubuntu/catkin_ws/src/controller/config/start.png')))
        self.buttonStart.setIconSize(QtCore.QSize(60,60))
        self.buttonStart.setStyleSheet("text-align: left;font-size: 24px")
        
        self.buttonReturn = QPushButton(' Return') #Return button
        self.vlayout.addWidget(self.buttonReturn)
        self.buttonReturn.clicked.connect(self.returnclicked)
        self.buttonReturn.show()
        self.buttonReturn.setIcon(QIcon(QPixmap('/home/ubuntu/catkin_ws/src/controller/config/return.jpg')))
        self.buttonReturn.setIconSize(QtCore.QSize(60,60))
        self.buttonReturn.setStyleSheet("text-align: left;font-size: 24px")
        self.buttonReturn.setEnabled(False)

        self.buttonStop = QPushButton(' STOP') #Stop button
        self.vlayout.addWidget(self.buttonStop)
        self.displays.addLayout(self.vlayout)
        self.mainvlayout.addLayout(self.displays)
        self.buttonStop.clicked.connect(self.stopclicked)
        self.buttonStop.show()
        self.buttonStop.setIcon(QIcon(QPixmap('/home/ubuntu/catkin_ws/src/controller/config/stop.jpg')))
        self.buttonStop.setIconSize(QtCore.QSize(60,60))
        self.buttonStop.setStyleSheet("text-align: left; font-size: 24px;")
        self.buttonStop.setEnabled(False)
        
        self.mainvlayout.addWidget(self.textbox) #Textbox display
        self.disp = ImageWidget(self)    
        self.displays.addWidget(self.disp)
        self.central.setLayout(self.mainvlayout)
        self.setCentralWidget(self.central)

        # self.mainMenu = self.menuBar()      # Menu bar
        # exitAction = QAction('&Exit', self)
        # exitAction.setShortcut('Ctrl+Q')
        # exitAction.triggered.connect(self.close)
        # self.fileMenu = self.mainMenu.addMenu('&File')
        # self.fileMenu.addAction(exitAction)
        self.w = None
        
        print "To set current location as Home, select Start" 

        
    def startClicked(self):
        QWidget.__init__(self)
        buttonReply = QMessageBox.question(self, 'start', " Current location will be set as Home. Continue?", QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
        self.text_update.connect(self.append_text) ###
        sys.stdout = self ###
        if buttonReply == QMessageBox.Yes:
            print('Drive robot to desired destination. To return Home, select Return')
            self.buttonStart.setEnabled(False)
            self.buttonReturn.setEnabled(True)
            self.buttonStop.setEnabled(True)
            self.buttonStop.setStyleSheet("text-align: left;background-color: red; font-size: 36px; color: white")
        else:
            print('Do nothing.')

    def returnclicked(self):
        QWidget.__init__(self)
        buttonReply = QMessageBox.question(self, 'Return to Home', "Robot will return Home. Continue?", QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
        self.text_update.connect(self.append_text) ###
        sys.stdout = self ###
        
        if buttonReply == QMessageBox.Yes:
            print('Robot is returning home')
            self.buttonStart.setEnabled(False)
            self.buttonReturn.setEnabled(False)
            self.buttonStop.setEnabled(True)
            self.buttonStop.setStyleSheet("text-align: left;background-color: red; font-size: 36px; color: white")
        else:
            print('Do nothing.')    
        
    def stopclicked(self):
        QWidget.__init__(self)  
        self.text_update.connect(self.append_text) ###
        sys.stdout = self ###
        print('Stop.')
        self.buttonStart.setEnabled(True)
        self.buttonReturn.setEnabled(False)
        self.buttonStop.setEnabled(False)
        self.buttonStop.setStyleSheet("text-align: left; font-size: 36px;")
        
    # Handle sys.stdout.write: update text display
    def write(self, text):
        self.text_update.emit(str(text))
    def flush(self):
        pass

    # Append to text display
    def append_text(self, text):
        cur = self.textbox.textCursor()     # Move cursor to end of text
        cur.movePosition(QTextCursor.End) 
        s = str(text)
        while s:
            head,sep,s = s.partition("\n")  # Split line at LF
            cur.insertText(head)            # Insert text at cursor
            if sep:                         # New line if LF
                cur.insertBlock()
        self.textbox.setTextCursor(cur)     # Update visible cursor

    # Start image capture & display
    def start(self):
        self.timer = QTimer(self)           # Timer to trigger display
        self.timer.timeout.connect(lambda: 
                    self.show_image(image_queue, self.disp, DISP_SCALE))
        self.timer.start(DISP_MSEC)         
        self.capture_thread = threading.Thread(target=grab_images, 
                    args=(image_queue, )) # must pass as tuples ;) the magic
        self.capture_thread.start()         # Thread to grab images

    # Fetch camera image from queue, and display it
    def show_image(self, imageq, display, scale):
        if not imageq.empty():
            image = imageq.get()
            if image is not None and len(image) > 0:
                self.display_image(image, display, scale)

    # Display an image, reduce size if required
    def display_image(self, img, display, scale=1):
        disp_size = img.shape[1]//scale, img.shape[0]//scale
        disp_bpl = disp_size[0] * 3
        #if scale > 1:
        #    img = cv2.resize(img, disp_size, 
        #                     interpolation=cv2.INTER_CUBIC)
        qimg = QImage(img.data, disp_size[0], disp_size[1], disp_bpl,
                      QImage.Format_RGB888)
        display.setImage(qimg)

    # Window is closing: stop video capture
    def closeEvent(self, event):
        global capturing
        capturing = False
        self.capture_thread.join()


#-------------------------------------------------------------------------------
if __name__ == '__main__':
    app = QApplication(sys.argv)
    win = MyWindow()
    win.showFullScreen()        # Occupied the full screen
    win.start()
    sys.exit(app.exec_())
#-------------------------------------------------------------------------------
#EOF
#-------------------------------------------------------------------------------
I know that I have to edit from line 75 to 80, but I just do not know how to start I have zero knowledge on python programming language.

The basic idea behind OSM_extension_FINALIZED.py is to process coordinate data output by a GPS receiver and display a corresponding map with a tracker on it to show the position of the receiver. The map has been downloaded onto the workstation. Thus, there is no need for an internet connection.

Below is the OSM_extension_FINALIZED.py,
from mpl_toolkits.basemap import Basemap
import matplotlib.pyplot as plt
from matplotlib.patches import Circle
import numpy as np
import datetime
import shutil
import sys
import threading
import time


import math
import urllib2
import StringIO
import requests
import serial 
from pynmea import nmea
import pynmea2
from io import BytesIO
from PIL import Image

i=0
alt = 0

def deg2num(lat_deg, lon_deg, zoom): #converts lat_deg and lon_deg to tile number
  lat_rad = math.radians(lat_deg)
  n = 2.0 ** zoom
  xtile = int((lon_deg + 180.0) / 360.0 * n)
  ytile = int((1.0 - math.log(math.tan(lat_rad) + (1 / math.cos(lat_rad))) / math.pi) / 2.0 * n)
  
  return (xtile, ytile)

def num2deg(xtile, ytile, zoom): #converts tile numer to lat_deg and lon_deg

  n = 2.0 ** zoom
  lon_deg = xtile / n * 360.0 - 180.0
  lat_rad = math.atan(math.sinh(math.pi * (1 - 2 * ytile / n)))
  lat_deg = math.degrees(lat_rad)

  return (lat_deg, lon_deg)

def getImageCluster(lat_deg, lon_deg, delta_lat,  delta_long, zoom):
    headers = {"User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36"}
    smurl = r"http://a.tile.openstreetmap.org/{0}/{1}/{2}.png"

    xmin, ymax = deg2num(lat_deg -0.0025, lon_deg -0.002, zoom) #Adjust lat/lon_deg to change the position of main tile
    xmax, ymin = deg2num(lat_deg + delta_lat, lon_deg +0.001 + delta_long, zoom)

    bbox_ul = num2deg(xmin, ymin, zoom) 
    bbox_ll = num2deg(xmin, ymax + 1, zoom)
    print '(UPPER LEFT), (LOWER LEFT)'
    print bbox_ul, bbox_ll
    print ' '

    bbox_ur = num2deg(xmax + 1, ymin, zoom)
    bbox_lr = num2deg(xmax + 1, ymax + 1, zoom)
    print '(UPPER RIGHT), (LOWER RIGHT)'
    print bbox_ur, bbox_lr
    print ' '

    Cluster = Image.new('RGB',((xmax-xmin+1)*256-1,(ymax-ymin+1)*256-1) ) 
    for xtile in range(xmin-1, xmax+1):
        for ytile in range(ymin-1,  ymax+1):
            try:
                imgurl = smurl.format(zoom, xtile, ytile)
                print("Opening: " + imgurl)
                tile = Image.open('SG_'+str(xtile)+'_'+str(ytile)+'.png') #SG_(column)_(row)
                Cluster.paste(tile, box = ((xtile-xmin)*256 ,  (ytile-ymin)*255))
            except: 
                print("Couldn't open image")
                tile = None


    return Cluster, [bbox_ll[1], bbox_ll[0], bbox_ur[1], bbox_ur[0]]

def check_serial():
    init_serial()

def init_serial(): #To configure and open the serial port
    global ser

    ser = serial.Serial(
        #port = '/dev/ttyACM0', #Use this for Linux
        port = 'COM10', #Use this for Windows
        baudrate = 38400,
        parity = serial.PARITY_NONE,
        stopbits = serial.STOPBITS_ONE,
        bytesize = serial.EIGHTBITS,
    )
    ser.timeout = 1
    ser.isOpen()
    
    print 'Opening ' + ser.name
    print ' '

    thread()

def stream_serial():

    line = ser.readline()
    
    # print "This is to annoy you."

def thread():
    #threads - run idependent of main loop
    thread1 = threading.Thread(target = save_raw) #saves the raw GPS data over serial while the main program runs
    # thread2 = threading.Thread(target = user_input) #optional second thread
    thread1.start()
    # thread2.start()

def save_raw():
    #this fxn creates a txt file and saves only GPGGA sentences
    while 1:
        line = ser.readline()
        line_str = str(line)
        if(line_str[4] == 'G'): # $GPGGA
            if(len(line_str) > 50): 
                # open txt file and log data
                f = open('nmea.txt', 'a')
                try:
                    f.write('{0:}'.format(line_str))
                finally:
                    f.close()
            else:
                stream_serial()

def position():
    
    f1 = open('temp.txt', 'w')
    f1.truncate() 
    shutil.copyfile('nmea.txt', 'temp.txt')
    f1.close()

    f1 = open('temp.txt', 'r')
    try:
        for line in f1:
            if(line[2] == 'N'): # forth character in $GNGGA
                if(len(line) > 50):
                    print line
                    msg = pynmea2.parse(line)
                    lat_deg = msg.latitude #msg is the object, latitude is the attribute
                    lon_deg = msg.longitude #msg is the object, longitude is the attribute

                    #shows that we are reading through this loop
                    print lat_deg
                    print lon_deg
    finally:
        f1.close()


    delta_lat, delta_long, zoom = 0.0012,  0.0015, 18 #Adjust delta_lat/lon to change the size of map
    a, bbox = getImageCluster(lat_deg, lon_deg, delta_lat,  delta_long, zoom)
    
    fig = plt.figure(figsize=(10, 10))
    ax = plt.subplot(111)
    m = Basemap(
        llcrnrlon=bbox[0], llcrnrlat=bbox[1],
        urcrnrlon=bbox[2], urcrnrlat=bbox[3],
        projection='merc', ax=ax
    )
    # list of points to display (long, lat)
    ls_points = [m(x,y) for x,y in [(lon_deg, lat_deg)]] #(base_lon,base_lat)]]
    m.imshow(a, interpolation='none', origin='upper') # origin = 'upper' reverse the Vertical axis direction.
    ax.scatter([point[0] for point in ls_points],
               [point[1] for point in ls_points],
               alpha = 0.9, color = 'r')
    print ' '
    print '(c) OpenStreetMap contributors'
    print ' '
    plt.show()



check_serial()

while 1:
     position()
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Integrating code with gui.py using modular math Pleiades 0 2,249 May-02-2018, 04:02 PM
Last Post: Pleiades
  [PyQt] integrating Pydesigner and python JackDinn 0 2,238 Mar-01-2018, 02:22 PM
Last Post: JackDinn

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020