1

So I'm working on a Jetson Nano running Ubuntu 18.04. I'd like to create a script that at startup automatically runs, taking a video feed from the connected webcam, and opening up a window to view the feed.

Before fully testing out my main script, I wanted to do a proof of concept that just opens up an image to display upon startup. To do so, I followed this tutorial to get a script to run on startup, and added the part to read & open the image: https://www.linuxshelltips.com/run-python-script-ubuntu-startup/

The modified script is this:

rom os.path import expanduser
import datetime
import cv2
import matplotlib
import matplotlib.pyplot as plt
from PIL import Image

img = cv2.imread('/home/sam/Documents/2022-08-31-220946_4.jpg')
window_name = 'test_img'

cv2.imshow(window_name,img)

while True:
    k = cv2.waitKey(0) & 0xFF
    if k==27:
        break
cv2.destroyAllWindows()

file = open(expanduser("~") + '/Desktop/i_was_created.txt', 'w')
file.write("This LinuxShellTips Tutorial Actually worked!\n" + str(datetime.datetime.now()))
file.write('OpenCV Version: {}\n'.format(str(cv2.__version__)))
file.write('Matplotlib Version: {}\n'.format(str(matplotlib.__version__)))
file.write('img size: {}\n'.format(str(img.shape)))
file.write('img size: {}'.format(str(image.format)))
file.close()

Now, when I run this script on startup, it doesn't work. The imshow() window doesn't appear anywhere, and the rest of the script doesn't execute after hitting the escape button. But, if I comment out the following lines, the script runs from start to finish without issue from startup:

cv2.imshow(window_name,img)

while True:
    k = cv2.waitKey(0) & 0xFF
    if k==27:
        break
cv2.destroyAllWindows()

So it seems the issue really does lie with the imshow() function. Testing with a simple

cv2.imshow('img',img)
cv2.waitKey(0)
cv2.destroyAllWindows()

instead also prevents the lines after from running.

However, when I run the script from the terminal manually, it works completely fine without issue, showing the image until the escape key is hit, then creating the txt file.

Also to note, using other image display libraries such as PIL & Matplotlib, and trying with a tkinter GUI lead to the same issue as well, so don't think it's necessarily specific to OpenCV.

I was told somewhere else it might be related to the graphical interfaces (X server or something) not being started yet, and that what I'm trying to accomplish may need to be modeled as a service, but this isn't something I know a whole lot about.

So, I'm wondering what's causing this issue, and how it might be able to be resolved. Any help anyone can offer is much appreciated!

1

1 Answer 1

2
+25

Most such tutorials neglect to explain dependencies – quite a few things happen during startup, and for some people "on startup" means "before event Y", while for others it means "after event Y", so whichever method you use to add a startup command without specifying what it needs, there's always a chance it'll run too early or too late.

But several points besides that:

On typical Linux distributions, what you broadly call "startup" consists of at least two major phases: the system startup (boot) and the user session startup (login). System startup generally ends before you've logged in, not after.

This has a lot to do with Linux supporting multiple concurrent GUI sessions; there is no shared system-wide GUI, but rather each logged-in user gets their own.

This means that your graphical environment (the X11 server "Xorg") only becomes available when you log in to Ubuntu – it is not available before login, and therefore not yet available when most services start (including when cron @reboot jobs are run).

In general, system services have no access to X at all – unless they're the ones which start Xorg in the first place (such as the service displaying the graphical login screen, which has a fully separate Xorg instance.)

The graphical login screen is itself a service, and a pretty late one at that, so things like cron typically start well before the login screen does. But even if you adjusted the order so that your app ran "after" the login screen, it would still not run with the privileges of the login screen – user A cannot access the GUI of user B, so cron jobs run under your own account won't have any access to the X server belonging to the login screen.

what I'm trying to accomplish may need to be modeled as a service

Generally yes; defining your own system service configuration would give you much more control over when it starts – you could explicitly specify "Before=this" or "After=that", instead of being tied to the "cron" service (which starts in parallel with most things and runs your @reboot job ~whenever~).

But if you want a GUI app to be visible on your regular Ubuntu desktop, it's typically the opposite – anything that displays a GUI window is not a system service and will give you headaches if you try to make it a system service. Instead, it should be started by the graphical environment itself, e.g. through the "XDG autostart" mechanism (~/.config/autostart) as mentioned here.


Exception to all of the above: Systems which are built as "appliances" (dedicated to a single GUI app) are configured to avoid user login completely, instead they have a service that starts X in a specific configuration without login, and then it becomes possible to have another service that starts the app within that predefined X environment.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.