Skip to content

Instantly share code, notes, and snippets.

@seongyooncho
Created July 22, 2025 13:09
Show Gist options
  • Select an option

  • Save seongyooncho/d48840aa33f7c3889edc83a85afaedf6 to your computer and use it in GitHub Desktop.

Select an option

Save seongyooncho/d48840aa33f7c3889edc83a85afaedf6 to your computer and use it in GitHub Desktop.
rpi setup
Commandline: apt install -y python3-picamera2 libcamera-apps
Commandline: apt install vim
Commandline: apt install -y python3-opencv
Commandline: apt install netcat-openbsd
Commandline: apt install libgtk2.0-dev libcanberra-gtk-module
Commandline: apt install libcap-dev
Commandline: apt install -y libcamera-dev libcamera-apps python3-libcamera
Commandline: apt install fonts-nanum fonts-noto-cjk
Commandline: apt install wmctrl xdotool
Commandline: apt install screen
Commandline: apt install hailo-all
argcomplete==2.0.0
asgiref==3.6.0
astroid==2.14.2
asttokens==2.2.1
attrs==25.3.0
av==14.4.0
Babel==2.10.3
beautifulsoup4==4.11.2
blinker==1.5
certifi==2025.4.26
chardet==5.1.0
charset-normalizer==3.4.2
click==8.1.3
colorama==0.4.6
colorzero==2.0
contextlib2==0.6.0.post1
cryptography==38.0.4
cupshelpers==1.0
dbus-python==1.3.2
dill==0.3.6
distlib==0.3.6
distro==1.8.0
docutils==0.19
ffpyplayer==4.5.3
filelock==3.9.0
Flask==2.2.2
future==0.18.2
gpiozero==2.0.1
hailort==4.20.0
html5lib==1.1
idna==3.10
importlib-metadata==4.12.0
isodate==0.7.2
isort==5.6.4
itsdangerous==2.1.2
jedi==0.18.2
Jinja2==3.1.2
jsonpointer==2.3
jsonschema==4.24.0
jsonschema-specifications==2025.4.1
lazy-object-proxy==1.9.0
lgpio==0.2.2.0
libarchive-c==5.3
libevdev==0.5
logilab-common==1.9.8
lxml==5.4.0
Mako==1.2.4.dev0
Markdown==3.4.1
MarkupSafe==2.1.2
mccabe==0.7.0
meson==1.5.1
more-itertools==8.10.0
mypy==1.0.1
mypy-extensions==0.4.3
netaddr==0.8.0
netifaces==0.11.0
numpy==1.24.2
oauthlib==3.2.2
olefile==0.46
onvif-zeep==0.2.12
parso==0.8.3
pexpect==4.8.0
pgzero==1.2
picamera2==0.3.27
pidng==4.0.9
piexif==1.1.3
pigpio==1.78
pillow==11.2.1
platformdirs==4.3.8
psutil==5.9.4
ptyprocess==0.7.0
pycairo==1.20.1
pycryptodomex==3.11.0
pycups==2.0.1
pygame==2.1.2
Pygments==2.14.0
PyGObject==3.42.2
pyinotify==0.9.6
PyJWT==2.6.0
pylint==2.16.2
PyOpenGL==3.1.6
pyOpenSSL==23.0.0
PyQt5==5.15.9
PyQt5-sip==12.11.1
pyrsistent==0.18.1
pyserial==3.5
pysmbc==1.0.23
python-apt==2.6.0
python-dotenv==0.21.0
python-prctl==1.8.1
pytz==2025.2
pyudev==0.24.0
PyYAML==6.0
referencing==0.36.2
reportlab==3.6.12
requests==2.32.4
requests-file==2.1.0
requests-oauthlib==1.3.0
requests-toolbelt==1.0.0
responses==0.18.0
rfc3987==1.3.8
roman==3.3
rpds-py==0.25.1
rpi-lgpio==0.6
RTIMULib==7.2.1
Send2Trash==1.8.1b0
sense-hat==2.6.0
simplejpeg==1.8.2
simplejson==3.18.3
six==1.16.0
smbus2==0.4.2
soupsieve==2.3.2
spidev==3.5
ssh-import-id==5.10
thonny==4.1.4
toml==0.10.2
tomlkit==0.11.7
tqdm==4.67.1
twython==3.8.2
types-aiofiles==22.1
types-annoy==1.17
types-appdirs==1.4
types-aws-xray-sdk==2.10
types-babel==2.11
types-backports.ssl-match-hostname==3.7
types-beautifulsoup4==4.11
types-bleach==5.0
types-boto==2.49
types-braintree==4.17
types-cachetools==5.2
types-caldav==0.10
types-certifi==2021.10.8
types-cffi==1.15
types-chardet==5.0
types-chevron==0.14
types-click-spinner==0.1
types-colorama==0.4
types-commonmark==0.9
types-console-menu==0.7
types-contextvars==2.4
types-croniter==1.3
types-cryptography==3.3
types-D3DShot==0.1
types-dateparser==1.1
types-DateTimeRange==1.2
types-decorator==5.1
types-Deprecated==1.2
types-dj-database-url==1.0
types-docopt==0.6
types-docutils==0.19
types-editdistance==0.6
types-emoji==2.1
types-entrypoints==0.4
types-first==2.0
types-flake8-2020==1.7
types-flake8-bugbear==22.10.27
types-flake8-builtins==2.0
types-flake8-docstrings==1.6
types-flake8-plugin-utils==1.3
types-flake8-rst-docstrings==0.2
types-flake8-simplify==0.19
types-flake8-typing-imports==1.14
types-Flask-Cors==3.0
types-Flask-SQLAlchemy==2.5
types-fpdf2==2.5
types-gdb==12.1
types-google-cloud-ndb==1.11
types-hdbcli==2.14
types-html5lib==1.1
types-httplib2==0.21
types-humanfriendly==10.0
types-invoke==1.7
types-JACK-Client==0.5
types-jmespath==1.0
types-jsonschema==4.17
types-keyboard==0.13
types-ldap3==2.9
types-Markdown==3.4
types-mock==4.0
types-mypy-extensions==0.4
types-mysqlclient==2.1
types-oauthlib==3.2
types-openpyxl==3.0
types-opentracing==2.4
types-paho-mqtt==1.6
types-paramiko==2.11
types-parsimonious==0.10
types-passlib==1.7
types-passpy==1.0
types-peewee==3.15
types-pep8-naming==0.13
types-Pillow==9.3
types-playsound==1.3
types-polib==1.1
types-prettytable==3.4
types-protobuf==3.20
types-psutil==5.9
types-psycopg2==2.9
types-pyaudio==0.2
types-PyAutoGUI==0.9
types-pycurl==7.45
types-pyfarmhash==0.3
types-pyflakes==2.5
types-Pygments==2.13
types-pyinstaller==5.6
types-PyMySQL==1.0
types-pynput==1.7
types-pyOpenSSL==22.1
types-pyRFC3339==1.1
types-PyScreeze==0.1
types-pysftp==0.2
types-pytest-lazy-fixture==0.6
types-python-crontab==2.6
types-python-dateutil==2.8
types-python-gflags==3.1
types-python-jose==3.3
types-python-nmap==0.7
types-python-slugify==6.1
types-pytz==2022.6
types-pyvmomi==7.0
types-pywin32==304
types-PyYAML==6.0
types-redis==4.3
types-regex==2022.10.31
types-requests==2.28
types-retry==0.9
types-Send2Trash==1.8
types-setuptools==65.5
types-simplejson==3.17
types-singledispatch==3.7
types-six==1.16
types-slumber==0.7
types-SQLAlchemy==1.4.43
types-stdlib-list==0.8
types-stripe==3.5
types-tabulate==0.9
types-termcolor==1.1
types-toml==0.10
types-toposort==1.7
types-tqdm==4.64
types-tree-sitter==0.20
types-tree-sitter-languages==1.5
types-ttkthemes==3.2
types-typed-ast==1.5
types-tzlocal==4.2
types-ujson==5.5
types-urllib3==1.26
types-vobject==0.9
types-waitress==2.1
types-whatthepatch==1.0
types-xmltodict==0.13
types-xxhash==3.0
types-zxcvbn==4.4
typing_extensions==4.14.0
uritemplate==4.1.1
urllib3==2.4.0
v4l2-python3==0.3.5
virtualenv==20.17.1+ds
webcolors==1.11.1
webencodings==0.5.1
Werkzeug==2.2.2
wrapt==1.14.1
zeep==4.3.1
zipp==1.0.0
import cv2
import time
import threading
import os
from onvif import ONVIFCamera
from picamera2 import Picamera2
# ================================
# RTSP Camera Setup
# ================================
RTSP_URL = "rtsp://admin:EdgePTZ%[email protected]/Stream/Live/101?transportmode=unicast&profile=ONFProfileToken_101"
cap = cv2.VideoCapture(RTSP_URL)
# ================================
# ONVIF Setup
# ================================
ip = '192.168.1.68'
port = 80
username = 'admin'
password = 'EdgePTZ#2025'
wsdl_path = 'wsdl'
print("Connecting to ONVIF camera...")
cam = ONVIFCamera(ip, port, username, password, wsdl_path)
media = cam.create_media_service()
ptz = cam.create_ptz_service()
profile = media.GetProfiles()[0]
def zoom(inout):
request = ptz.create_type('ContinuousMove')
request.ProfileToken = profile.token
request.Velocity = {'Zoom': {'x': 0.9 * inout}}
ptz.ContinuousMove(request)
def stop_zoom():
ptz.Stop({'ProfileToken': profile.token})
# ================================
# PiCamera2 Setup
# ================================
picam2 = Picamera2()
config = picam2.create_preview_configuration(
main={"size": (640, 480), "format": "RGB888"},
controls={"FrameDurationLimits": (33333, 33333)} # Target ~30 FPS
)
picam2.configure(config)
picam2.start()
# ================================
# Threaded Capture Classes
# ================================
class CameraThread(threading.Thread):
def __init__(self, name, capture_func):
super().__init__(daemon=True)
self.name = name
self.capture_func = capture_func
self.frame = None
self.running = True
self.lock = threading.Lock()
def run(self):
while self.running:
frame = self.capture_func()
if frame is not None:
with self.lock:
self.frame = frame
time.sleep(0.01) # avoid CPU spinning
def get_frame(self):
with self.lock:
return self.frame.copy() if self.frame is not None else None
def stop(self):
self.running = False
# RTSP and PiCamera capture functions
def capture_rtsp():
ret, frame = cap.read()
return frame if ret else None
def capture_picam():
return picam2.capture_array()
# Initialize threads
rtsp_thread = CameraThread("RTSP", capture_rtsp)
picam_thread = CameraThread("PiCam", capture_picam)
rtsp_thread.start()
picam_thread.start()
print("Press 'z' to zoom in, 'x' to zoom out, space to stop zoom, 'q' to quit.")
# Prepare main and preview windows once
cv2.namedWindow("RTSP View", cv2.WINDOW_NORMAL)
cv2.setWindowProperty("RTSP View", cv2.WND_PROP_FULLSCREEN, cv2.WINDOW_FULLSCREEN)
cv2.namedWindow("PiCam Preview", cv2.WINDOW_NORMAL)
cv2.resizeWindow("PiCam Preview", 320, 240)
cv2.moveWindow("PiCam Preview", 100, 100)
try:
while True:
frame1 = rtsp_thread.get_frame()
frame2 = picam_thread.get_frame()
if frame1 is not None:
frame1 = cv2.rotate(frame1, cv2.ROTATE_180)
cv2.imshow("RTSP View", frame1)
if frame2 is not None:
frame2 = cv2.rotate(frame2, cv2.ROTATE_180)
cv2.imshow("PiCam Preview", frame2)
key = cv2.waitKey(1) & 0xFF
if key == ord('q'):
break
elif key == ord('z'):
zoom(+1)
elif key == ord('x'):
zoom(-1)
elif key == ord(' '):
stop_zoom()
time.sleep(1 / 30) # display loop throttle
finally:
# Cleanup
print("Stopping threads...")
rtsp_thread.stop()
picam_thread.stop()
cap.release()
cv2.destroyAllWindows()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment