animation/fourcell/apply_image.py

195 lines
5.6 KiB
Python
Raw Normal View History

import argparse
import sys
import cv2
import numpy as np
from json import load
from os.path import exists, basename
from common import image_resize, display, read_json
holeConstant = .0156862745 # 160/10200
fontConstant = 96
markConstant = 5
linesConstant = 150
def generate_text (text, fontSize, rotation) :
2023-03-18 23:10:11 +00:00
rgb_color=(255,255,255)
color = tuple(reversed(rgb_color))
(w, h), baseline = cv2.getTextSize(text, cv2.FONT_HERSHEY_PLAIN, fontSize, 2)
image = np.zeros((h + baseline, w, 3), np.uint8)
image[:] = color
image = cv2.cvtColor(image, cv2.COLOR_BGR2BGRA)
image = cv2.putText(image, text, (0, h + round(baseline/2)), cv2.FONT_HERSHEY_PLAIN, fontSize, [0, 0, 0], 2, cv2.LINE_AA)
if rotation == 90 :
image = cv2.rotate(image, cv2.ROTATE_90_CLOCKWISE)
elif rotation == -90 :
image = cv2.rotate(image, cv2.ROTATE_90_COUNTERCLOCKWISE)
return image
def place_text (output, text_image, i, points) :
2023-03-18 23:10:11 +00:00
height, width = text_image.shape[:2]
halfW = int(round(width / 2))
halfH = int(round(height / 2))
2023-03-18 23:10:11 +00:00
if i == 0 or i == 1 :
y = int(round((points['0']['y'] + points['1']['y']) / 2))
x = int(round((points['0']['x'] + points['1']['x']) / 2)) - width
elif i == 2 or i == 3 :
y = int(round((points['0']['y'] + points['1']['y']) / 2))
x = int(round((points['0']['x'] + points['1']['x']) / 2)) + width
output[y-halfH:y-halfH+height, x-halfW:x-halfW+width] = text_image
return output
def to_rotation (i) :
if i == 0 or i == 1 :
return -90
2023-03-18 23:10:11 +00:00
if i == 2 or i == 3 :
return 90
def to_text (fileName, project_name) :
parts = fileName.split('.')
name = parts[0]
if 'guide_' in name :
return project_name
parts = name.split('_')
return parts[len(parts)-1]
# use top left, top right, bottom left
def apply_image_to_points (original, target, points) :
rows, cols, ch = original.shape
ir, ic, ich = target.shape
print('Using points: ')
print(points)
atPts = np.float32(points)
targetPts = np.float32([[0, 0], [ic, 0], [0, ir]])
M = cv2.getAffineTransform(targetPts, atPts)
2023-02-20 23:54:08 +00:00
dst = cv2.warpAffine(target, M, (cols, rows),
flags = cv2.INTER_CUBIC,
borderMode = cv2.BORDER_CONSTANT,
borderValue = [0, 0, 0, 0])
2023-02-20 23:54:08 +00:00
mask = get_mask(dst)
return combine_images(original, dst, mask)
def create_blank(width, height):
rgb_color=(255,255,255)
image = np.zeros((height, width, 3), np.uint8)
color = tuple(reversed(rgb_color))
image[:] = color
2023-02-10 03:17:18 +00:00
#return image
return cv2.cvtColor(image, cv2.COLOR_BGR2BGRA)
# get points 0, 1 and 3 = top left, top right and bottom left
def to_points (d) :
return [[d['0']['x'], d['0']['y']], [d['1']['x'], d['1']['y']], [d['3']['x'], d['3']['y']]]
def get_mask (img) :
lower = np.array([0,0,0,0])
upper= np.array([0,0,0,0])
mask = cv2.inRange(img, lower, upper)
return cv2.bitwise_not(mask)
def combine_images (bg, fg, mask) :
fk = cv2.bitwise_or(fg, fg, mask=mask)
mask = cv2.bitwise_not(mask)
bk = cv2.bitwise_or(bg, bg, mask=mask)
return cv2.bitwise_or(fk, bk)
def draw_registration_marks (output, points, registrationMark, lines) :
keys = list(points.keys())
for key in keys:
output = draw_registration_mark(output, points[key], registrationMark, lines)
return output
def draw_registration_mark (output, point, registrationMark, lines) :
half = int(round(registrationMark / 2))
topY = point['y'] - half
bottomY = point['y'] + half
leftX = point['x'] - half
rightX = point['x'] + half
cv2.line(output, (leftX, point['y'],), (rightX, point['y'],), [0, 0, 0], lines)
cv2.line(output, (point['x'], topY,), (point['x'], bottomY,), [0, 0, 0], lines)
return output
def apply_image (args) :
if not exists(args.template) :
print('Calibration template does not exist, please provide one that does')
exit(3)
if len(args.images) < 1:
print('Please provide at least one image to apply')
exit(4)
if len(args.images) > 4:
print('Please provide maximum four images to apply')
exit(5)
for img in args.images:
if not exists(img) :
print(f'Image {img} does not exist, exiting...')
exit(6)
print('Using images: ')
for img in args.images:
print(f' -> {basename(img)}')
tmpl = read_json(args.template)
print(f"Image size {tmpl['width']}x{tmpl['height']}")
hole = round(tmpl['width'] * holeConstant)
blank = create_blank(tmpl['width'], tmpl['height'])
dpi = round(tmpl['width'] / 8.5)
fontSize = round(dpi / fontConstant)
registrationMark = int(round(dpi / markConstant))
lines = int(round(dpi / linesConstant))
#blank = cv2.imread(args.template.replace('.calibration.json', ''))
output = blank.copy()
hp = tmpl['holePunches']
for i in hp:
print(hp[i])
cv2.circle(output, (hp[i]['x'], hp[i]['y'],), hole, (200, 200, 200,), -1)
for i in range(0, len(args.images)) :
print(args.images[i])
frame = cv2.imread(args.images[i])
frame = cv2.cvtColor(frame, cv2.COLOR_RGB2RGBA)
#cv2.imwrite(f'test{i}.png', output)
output = apply_image_to_points(output, frame, to_points(tmpl[f'{i}']))
rotation = to_rotation(i)
text = to_text(basename(args.images[i]), args.name)
text_image = generate_text(text, fontSize, rotation)
output = place_text(output, text_image, i, tmpl[f'{i}'])
output = draw_registration_marks(output, tmpl[f'{i}'], registrationMark, lines)
print(f'Applied {basename(args.images[i])}')
output = cv2.cvtColor(output, cv2.COLOR_BGRA2BGR)
#display(output)
cv2.imwrite(args.destination, output)
##print(f'Wrote {args.destination}')
def main () :
parser = argparse.ArgumentParser()
parser.add_argument('name', help='Name of project')
parser.add_argument('destination', help='File to output image to')
parser.add_argument('template', help='Template file to use')
parser.add_argument('images', nargs=argparse.REMAINDER)
args = parser.parse_args()
apply_image(args)
main()