Movie integration & more parameters

master
kaqu 2020-05-21 11:59:19 +02:00
parent 0e398df51d
commit 7b2978ea76
5 changed files with 99 additions and 48 deletions

View File

@ -13,30 +13,38 @@
<entry>
<title type="text">Disclaimer: This IS fake news (says a cretan).</title>
<id>file://FakeNews.xml/3</id>
<id>file://FakeNews.xml/0</id>
<updated>2020-05-11T13:16:00+02:00</updated>
<published>2020-05-11T13:16:00+02:00</published>
<published>2020-05-11T09:23:00+02:00</published>
<link href="file://FakeNews.xml"/>
<summary type="html">This is message #3</summary>
<summary type="html">This is message #0</summary>
</entry>
<entry>
<title type="text">National Enquirer: hacKNology may be part of deep state.</title>
<title type="text">Reptiloids warn: hacKNology seeks new world order!</title>
<id>file://FakeNews.xml/2</id>
<updated>2020-05-12T06:55:00+02:00</updated>
<published>2020-05-12T06:55:00+02:00</published>
<link href="file://FakeNews.xml"/>
<summary type="html">This is message #2</summary>
</entry>
<entry>
<title type="text">Reptiloids warn: hacKNology seeks world domination!</title>
<id>file://FakeNews.xml/1</id>
<updated>2020-05-12T11:13:00+02:00</updated>
<published>2020-05-12T11:13:00+02:00</published>
<link href="file://FakeNews.xml"/>
<summary type="html">This is message #1</summary>
<summary type="html">This is message #2</summary>
</entry>
<entry>
<title type="text">National Enquirer: hacKNology may be part of deep state.</title>
<id>file://FakeNews.xml/3</id>
<updated>2020-05-12T06:55:00+02:00</updated>
<published>2020-05-12T06:55:00+02:00</published>
<link href="file://FakeNews.xml"/>
<summary type="html">This is message #3</summary>
</entry>
<entry>
<title type="text">OAN: hacKNology's hidden agenda revealed - subdue 'ordinary americans'!</title>
<id>file://FakeNews.xml/4</id>
<updated>2020-05-19T17:45:00+02:00</updated>
<published>2020-05-19T17:56:00+02:00</published>
<link href="file://FakeNews.xml"/>
<summary type="html">This is message #4</summary>
</entry>
</feed>

View File

@ -9,6 +9,11 @@ I added a functioning one (store as /etc/akvcam/config.ini - w/ root rights!).
Also: You will need a 3rd gen. Intel i7/equivalent or better ...
21.05.20 New/improved features
Permit background movie play (w/o sound)
Introduced coordinates & many more parameters
17.05.20 New/improved features
3D text background elements

View File

@ -18,6 +18,8 @@ History:
Argument parsing improved
16.05.20/KQ More 3D elements now
17.05.20/KQ TrueType fonts integrated (via PIL/pillow)
19.05.20/KQ Permit background movie play (w/o sound)
21.05.20/KQ Introduced coordinates as parameters
"""
import argparse
@ -28,17 +30,18 @@ import datetime, time
import cv2
import feedparser # To install: Activate (cv) environment, then 'pip3 install feedparser'
parser = argparse.ArgumentParser(prog='python3 funcam.py', usage="%(prog)s --webcam <n> [--id '<ID>'][--rss '<url>'][--logo '<png>'][--alarm HH:MM][--altb '<path>'][--d3d][--ttf]",
parser = argparse.ArgumentParser(prog='python3 funcam.py', usage="%(prog)s --webcam <n> [--id <ID>][--rss <url>][--logo <x> <y> <w> <h> <s1> <s2> <png>][--alarm HH:MM][--altb <path>][--d3d][--ttf <font>][--movie <x> <y> <w> <h> <path>]",
description='A stream modification utility',
epilog="Dont't forget to redirect stdout to the video device")
parser.add_argument('--webcam', type=int, choices=[0, 1, 2, 3, 4], nargs='?', help='Webcam index 0..4, will be used to access webcam device /dev/video<n>', required=True)
parser.add_argument('--id', nargs='?', help='Id data shown on the occassional nameplate')
parser.add_argument('--rss', nargs='?', help='RSS feed link')
parser.add_argument('--logo', nargs='?', help='Station logo shown in upper left of output stream')
parser.add_argument('--logo', nargs=7, help='Station logo @x,y w/ w,h, subtext lines <s1> & <s2>')
parser.add_argument('--alarm', nargs='?', help='Alarm time, format as HH:MM')
parser.add_argument('--altb', nargs='?', help='Alternate background image path')
parser.add_argument('--d3d', action='store_true', help='Draw w/ 3D elements')
parser.add_argument('--ttf', action='store_true', help='Use TrueType fonts')
parser.add_argument('--ttf', nargs='?', help='Use TrueType font <font>')
parser.add_argument('--movie', nargs=5, help='Display a background movie @x,y w/ w,h')
args = parser.parse_args()
print("\n<<< funcam started ... >>>",file=sys.stderr)
@ -51,7 +54,7 @@ print("Using webcam on : /dev/video"+str(args.webcam),file=sys.stder
if args.id != None:
print("ID will be : \'"+args.id+"\'",file=sys.stderr)
if args.logo != None:
print("Logo image file used : \'"+args.logo+"\'",file=sys.stderr)
print("Logo image file used : \'"+args.logo[6]+"\' x/y=" + str(args.logo[0])+"/"+str(args.logo[1])+" w/h="+str(args.logo[2])+"/"+str(args.logo[3])+ " \'"+args.logo[4]+"\',\'"+args.logo[5]+"\'",file=sys.stderr)
if args.rss != None:
print("RSS feed : \'"+args.rss+"\'",file=sys.stderr)
if args.alarm != None:
@ -66,8 +69,10 @@ if args.altb != None:
print("Alternate background (beta!): \'"+args.altb+"\'",file=sys.stderr)
if args.d3d:
print("3D element draw : Enabled",file=sys.stderr)
if args.ttf:
print("TrueType fonts : Enabled",file=sys.stderr)
if args.ttf != None:
print("TrueType font : "+args.ttf+ " (from /usr/share/fonts)",file=sys.stderr)
if args.movie != None:
print("Background movie : \'"+args.movie[4]+"\' x/y=" + str(args.movie[0])+"/"+str(args.movie[1])+" w/h="+str(args.movie[2])+"/"+str(args.movie[3]),file=sys.stderr)
# Prepare scroll line message as an RSS feed. Currently, this is only read once upon start ...
if args.rss != None:
@ -81,7 +86,7 @@ if args.rss != None:
rss_n = 10
#try:
msg = "+++ "
for i in range(0,rss_n-1,1):
for i in range(0,rss_n,1):
try:
msg = msg + datetime.datetime.strptime(d.entries[i].published,'%Y-%m-%dT%H:%M:%S+02:00').strftime('%H:%M')\
+ " " + d.entries[i].title + " +++ "
@ -95,16 +100,18 @@ if args.rss != None:
# Prepare station emblem data
if args.logo != None:
src1 = cv2.imread(args.logo,-1)
src1 = cv2.imread(args.logo[6],-1)
if src1 is None:
print("*** " + args.logo + " not found!",file=sys.stderr)
print("*** " + args.logo[6] + " not found!",file=sys.stderr)
exit(-1)
scr_width = 40 # Initial (full) width
x_offset = int(args.logo[0]) #12
y_offset = int(args.logo[1]) #12
max_scr_width = int(args.logo[2]) #100/40 # Initial (full) width
scr_width = max_scr_width
scr_height = int(args.logo[3]) #60 # Height
scr_sign = -1 # Start shrinking
alpha = 0.5 # 0.5 (0..1)
beta = (1.0 - alpha)
x_offset = 12 #6
y_offset = 12
# Prepare 3D background elements
if args.d3d:
@ -126,7 +133,7 @@ if args.d3d:
exit(-1)
imgRed3d = cv2.resize(imgRed3d, (640-500,480-432)) # w/h
if args.ttf: # TrueType fonts enabled?
if args.ttf != None: # TrueType fonts enabled?
# Pillow used for TrueType font integration
from PIL import Image, ImageFont, ImageDraw # To install: Activate (cv) environment, then 'pip3 install pillow'
@ -135,10 +142,22 @@ if args.ttf: # TrueType fonts enabled?
# https://pillow.readthedocs.io/en/2.8.1/reference/ImageFont.html
# https://stackoverflow.com/questions/37191008/load-truetype-font-to-opencv
# Use a TrueType font from /usr/shar/fonts (search for *.ttf!)
# Use a TrueType font from /usr/share/fonts (search for *.ttf!)
# Bold small fonts: Liberation Sans Narrow Bold, Nimbus Sans L Bold Condensed, Ubuntu Condensed Bold
regularfont = ImageFont.truetype("DejaVuSansCondensed-Bold.ttf", 44) # Height for clock
boldfont = ImageFont.truetype("DejaVuSansCondensed-Bold.ttf", 24) # Height for scroll line
regularfont = ImageFont.truetype(args.ttf, 44) #"DejaVuSansCondensed-Bold.ttf", 44) # Height for clock
boldfont = ImageFont.truetype(args.ttf,24) #"DejaVuSansCondensed-Bold.ttf", 24) # Height for scroll line
# Prepare background movie
if args.movie != None:
movie_x = int(args.movie[0]) #100
movie_y = int(args.movie[1]) #180
movie_w = int(args.movie[2]) #150
movie_h = int(args.movie[3]) #100
movie = cv2.VideoCapture(args.movie[4])
if not movie.isOpened(): #if not open already
movie.open() #make sure, we will have data
else:
movie = None
# Prepare background 'greenscreen'
if alternate_background != None:
@ -269,21 +288,37 @@ while(cap.isOpened()):
mm = int(time.strftime("%M", time.localtime()))
# Now: The fun stuff! ------------------------------------------
if alternate_background != None: # Green screen look-a-like pipeline
frame = do_alternate_background(frame,background_frame,alternate_frame)
if movie != None: # Play a movie?
try:
ret, fmovie = movie.read() # Next frame ...
#ret, fmovie = movie.read() # Next frame ... (speed-up nec.!)
fmovie = cv2.resize(fmovie, (movie_w,movie_h)) # w/h
alternate_frame2 = alternate_frame.copy()
alternate_frame2[movie_y:movie_y+movie_h, movie_x:movie_x+movie_w] = fmovie[0:movie_h, 0:movie_w] # Select 'ROI' only: y1:y2, x1:x2
except Exception as em: # EOF?
#print(str(em),file=sys.stderr)
movie.release() # Free former
movie = cv2.VideoCapture(args.movie[4]) # Re-open again
if not movie.isOpened(): #if not open already
movie.open() #make sure, we will have data
alternate_frame2 = alternate_frame.copy()
else:
alternate_frame2 = alternate_frame.copy()
frame = do_alternate_background(frame,background_frame,alternate_frame2)
# Emblem stancil (requires BGRA color space!)
if args.logo != None:
scr_width = scr_width + scr_sign
if scr_width <= 4:
scr_sign = 1 # Start increasing
if scr_width >= 100:
if scr_width >= max_scr_width:
scr_sign = -1 # & shrinking again
src2 = cv2.resize(src1, (scr_width,60)) # w/h
src2 = cv2.resize(src1, (scr_width,scr_height)) # w/h
overlay_image_alpha(frame,
src2[:, :, 0:3],
(x_offset+((100-scr_width)//2), y_offset),
(x_offset+((max_scr_width-scr_width)//2), y_offset),
src2[:, :, 3] / 255.0)
if args.d3d:
@ -297,15 +332,15 @@ while(cap.isOpened()):
# Emblem subtext
if args.logo != None:
cv2.putText(frame4, " LIVE",
(4,y_offset+64), # x,y
cv2.putText(frame4, args.logo[4], #" LIVE",
(x_offset-8,y_offset+scr_height+4), # x,y
(cv2.FONT_HERSHEY_DUPLEX), # Font
0.4, # Scaling
(255, 255, 255), # RGB
1, # Thickness
cv2.LINE_AA)
cv2.putText(frame4, "Constance/Germany",
(4,y_offset+72), # x,y
cv2.putText(frame4, args.logo[5], #"Constance/Germany",
(x_offset-8,y_offset+scr_height+12), # x,y
(cv2.FONT_HERSHEY_DUPLEX), # Font
0.4, # Scaling
(255, 255, 255), # RGB
@ -373,7 +408,7 @@ while(cap.isOpened()):
(640,480), # Bottom right
(255,255,255), # Color
-1) # Thickness (-1=opaque/no border
if args.ttf:
if args.ttf != None:
imgPil = Image.fromarray(frame4) # Unfortunately nec. ... (OpenCV->PIL)
draw = ImageDraw.Draw(imgPil) # Get a drawing handle (?!)
draw.text((scroll_x, 452), msg, font=boldfont, fill=(16,16,16,0)) # Draw actual message
@ -400,7 +435,7 @@ while(cap.isOpened()):
(200,200,200), # Color
1) # Thickness
scroll_x = scroll_x - 6
if scroll_x < -lenmsg*6*3: # was: -500 ...
if scroll_x < -lenmsg*4.5*3: # was: -500 ...
scroll_x = 500
# Time output
@ -440,7 +475,7 @@ while(cap.isOpened()):
(638,480), # Bottom right
(80,80,80), # Color
2) # Thickness (-1=opaque/no border)
if args.ttf:
if args.ttf != None:
imgPil = Image.fromarray(frame4) # Unfortunately nec. ... (OpenCV->PIL)
draw = ImageDraw.Draw(imgPil) # Get a drawing handle (?!)
draw.text((506, 432), t, font=regularfont, fill=(16,16,16,0)) # Draw actual message
@ -480,5 +515,7 @@ while(cap.isOpened()):
break
cap.release()
if movie != None:
movie.release()
print("\n<<< funcam terminated. >>>\n",file=sys.stderr)

BIN
spaceships.mp4 Normal file

Binary file not shown.

View File

@ -7,6 +7,7 @@
# 05.05.20/KQ Initial version
# 09.05.20/KQ Automatic virtual port detection (via getvirtualvideo.py), several fixed values turned into parameters
# 12.05.20/KQ Local RSS feed added, more parameters ...
# 21.05.20/KQ A LOT more parameters now!
#
# 1. Install akvcam virtual camera devices
# 2. Activate (cv) environment script
@ -43,9 +44,9 @@ echo ""
echo "*** For best video conference experience (currently, 5/2020) use chromium-browser ..."
# Alternate background (beta) not activated by default
# python3 funcam.py --webcam $WEBCAM --id "$NAMEPLATE" --logo emblem.png --rss "https://www.heise.de/security/rss/news-atom.xml" --d3d --altb alternate_background.jpg > $CAMPORT
# python3 funcam.py --webcam $WEBCAM --id "$NAMEPLATE" --logo emblem.png --rss "file://$PWD/FakeNews.xml" --alarm 21:50 --d3d > $CAMPORT
python3 funcam.py --webcam $WEBCAM --id "$NAMEPLATE" --logo emblem.png --rss "https://www.hacknology.de/index.xml" --d3d --ttf > $CAMPORT
# python3 funcam.py --webcam $WEBCAM --id "$NAMEPLATE" --logo 12 12 100 60 ' LIVE' 'Constance/Germany' emblem.png --rss "https://www.heise.de/security/rss/news-atom.xml" --d3d --altb alternate_background.jpg > $CAMPORT
# python3 funcam.py --webcam $WEBCAM --id "$NAMEPLATE" --logo 12 12 100 60 ' LIVE' 'Constance/Germany' emblem.png --rss "file://$PWD/FakeNews.xml" --alarm 21:50 --d3d --ttf DejaVuSansCondensed-Bold.ttf --altb alternate_background.jpg --movie 100 180 150 100 spaceships.mp4 > $CAMPORT
python3 funcam.py --webcam $WEBCAM --id "$NAMEPLATE" --logo 12 12 100 60 ' LIVE' 'Constance/Germany' emblem.png --rss "https://www.hacknology.de/index.xml" --d3d --ttf DejaVuSansCondensed-Bold.ttf > $CAMPORT
echo "Removing virtual (camera) devices ..."
sudo rmmod akvcam.ko