Any update?
Yes, you are not configuring the IP properly.
The IP is repeating the image first row over and over because stride is 0. Documentation Portal
You can use the driver below to work with the IP. Even though the pixels are supposed to be packed in 3 bytes, in my case, only the overlay_1_with_extra_channel
method works. I also wasn’t able to make the scale work, so if you can make it work I appreciate if you can provide an update.
video_mixer_regs = {
'CTRL':
{'address_offset': 0, 'size': 32, 'access': 'read-write', 'description': 'Control signals', 'fields': {
'ap_start': {'bit_offset': 0, 'bit_width': 1, 'description': 'Control signals', 'access': 'read-write'},
'ap_done': {'bit_offset': 1, 'bit_width': 1, 'description': 'Control signals', 'access': 'read-only'},
'ap_idle': {'bit_offset': 2, 'bit_width': 1, 'description': 'Control signals', 'access': 'read-only'},
'ap_ready': {'bit_offset': 3, 'bit_width': 1, 'description': 'Control signals', 'access': 'read-only'},
'flush_pending': {'bit_offset': 5, 'bit_width': 1, 'description': 'Flush pending AXI transactions', 'access': 'read-write'},
'flush_done': {'bit_offset': 6, 'bit_width': 1, 'description': 'Flush Done', 'access': 'read-only'},
'auto_restart': {'bit_offset': 7, 'bit_width': 1, 'description': 'Control signals', 'access': 'read-write'}}
},
'GIER': {'address_offset': 4, 'size': 32, 'access': 'read-write', 'description': 'Global Interrupt Enable Register', 'fields': {
'Enable': {'bit_offset': 0, 'bit_width': 1, 'description': 'Global Interrupt Enable Register', 'access': 'read-write'}}
},
'IP_IER': {'address_offset': 8, 'size': 32, 'access': 'read-write', 'description': 'IP Interrupt Enable Register', 'fields': {
'ap_done': {'bit_offset': 0, 'bit_width': 1, 'description': 'IP Interrupt Enable Register', 'access': 'read-write'},
'ap_ready': {'bit_offset': 1, 'bit_width': 1, 'description': 'IP Interrupt Enable Register', 'access': 'read-write'}}
},
'IP_ISR': {'address_offset': 12, 'size': 32, 'access': 'read-write', 'description': 'IP Interrupt Status Register', 'fields': {
'ap_done': {'bit_offset': 0, 'bit_width': 1, 'description': 'IP Interrupt Status Register', 'access': 'read-only'},
'ap_ready': {'bit_offset': 1, 'bit_width': 1, 'description': 'IP Interrupt Status Register', 'access': 'read-only'}}
},
'Width': {'address_offset': 16, 'size': 32, 'access': 'read-write', 'description': 'Active width of background'},
'Height': {'address_offset': 24, 'size': 32, 'access': 'read-write', 'description': 'Active height of background'},
'background_r_or_y': {'address_offset': 40, 'size': 32, 'access': 'read-write', 'description': 'Red or Y value of background color'},
'background_u_or_g': {'address_offset': 48, 'size': 32, 'access': 'read-write', 'description': 'Green or U value of background color'},
'background_g_or_u': {'address_offset': 56, 'size': 32, 'access': 'read-write', 'description': 'Blue or V value of background color'},
'layer_enabled': {'address_offset': 64, 'size': 32, 'access': 'read-write', 'description': 'Layer enable', 'fields': {
'master_layer': {'bit_offset': 0, 'bit_width': 1, 'description': 'Master layer is enabled/disabled', 'access': 'read-write'},
'overlay_layer_1': {'bit_offset': 1, 'bit_width': 1, 'description': 'Overlay Layer 1 is enabled/disabled', 'access': 'read-write'},
'logo_layer': {'bit_offset': 23, 'bit_width': 1, 'description': 'Logo layer is enabled/disabled', 'access': 'read-write'}
}},
'layer_1_alpha': {'address_offset': 512, 'size': 32, 'access': 'read-write', 'description': 'Alpha blending value for layer 1'},
'layer_1_start_x': {'address_offset': 520, 'size': 32, 'access': 'read-write', 'description': 'X position of the top left corner of layer 1, relative to the background layer'},
'layer_1_start_y': {'address_offset': 528, 'size': 32, 'access': 'read-write', 'description': 'Y position of the top left corner of layer 1, relative to the background layer'},
'layer_1_width': {'address_offset': 536, 'size': 32, 'access': 'read-write', 'description': 'Active width (in pixels) of layer 1'},
'layer_1_stride': {'address_offset': 544, 'size': 32, 'access': 'read-write', 'description': 'Active stride (in bytes) of layer 1'},
'layer_1_height': {'address_offset': 552, 'size': 32, 'access': 'read-write', 'description': 'Active height (in lines) of layer 1'},
'layer_1_scale_factor': {'address_offset': 560, 'size': 32, 'access': 'read-write', 'description': 'Scale factor for layer 1'},
'layer_1_plane_1_buffer': {'address_offset': 576, 'size': 32, 'access': 'read-write', 'description': 'Start address of plane 1 of frame buffer for layer 1'}
}
from pynq import allocate
import cv2
class VideoMixer(DefaultIP):
"""Video Mixer"""
bindto = ['xilinx.com:ip:v_mix:5.2']
def __init__(self, description):
description['registers'] = video_mixer_regs
super().__init__(description=description)
def start(self):
"""Populate the image resolution and start the IP"""
file = "/tmp/resolution.json"
if os.path.exists(file):
with open(file, "r", encoding='utf8') as f:
reso = json.load(f)
self._cols, self._rows = reso["width"], reso["height"]
else:
self._cols, self._rows = _cols, _rows
self.write(16, int(self._cols))
self.write(24, int(self._rows))
self.register_map.layer_enabled.master_layer = 1
self.write(0x00, 0x81)
def overlay_1(self, filename, scale:int=0):
"""This one is almost working"""
img = cv2.imread(filename)
self.logo = allocate(img.shape, dtype=np.uint8)
self.logo[:] = img[:]
self.register_map.layer_1_alpha = 200
self.register_map.layer_1_start_x = 100
self.register_map.layer_1_start_y = 200
self.register_map.layer_1_width = img.shape[1] * (2**scale)
self.register_map.layer_1_height = img.shape[0] * (2**scale)
self.register_map.layer_1_stride = img.shape[1] * img.shape[2]
self.register_map.layer_1_scale_factor = int(scale)
self.register_map.layer_1_plane_1_buffer = self.logo.physical_address
self.register_map.layer_enabled.overlay_layer_1 = 1
def overlay_1_with_extra_channel(self, filename, scale:int=0):
"""This one is working"""
img = cv2.imread(filename)
rgba = cv2.cvtColor(img, cv2.COLOR_RGB2RGBA)
self.logo = allocate(rgba.shape, dtype=np.uint8)
self.logo[:] = rgba[:]
self.register_map.layer_1_alpha = 200
self.register_map.layer_1_start_x = 100
self.register_map.layer_1_start_y = 200
self.register_map.layer_1_width = rgba.shape[1] * (2**scale)
self.register_map.layer_1_height = rgba.shape[0] * (2**scale)
self.register_map.layer_1_stride = rgba.shape[1] * rgba.shape[2]
self.register_map.layer_1_scale_factor = int(scale)
self.register_map.layer_1_plane_1_buffer = self.logo.physical_address
self.register_map.layer_enabled.overlay_layer_1 = 1
def disable_overlays(self):
self.register_map.layer_enabled = 0x1
Yes, it is working now with stride. I have set the stride to triple the image width (each pixel has 3byte). But the color needs to be shifted when loading the image (because of the color space I think).
logo[:]= cv2.imread('mirror.png')[:,:, [2, 0,1]]
I will try the scale and give an update later on. The others seem to have no problem, even with multiple layers with rgb8 only.
Thanks for your support.
Scaling is also working for me. You have to enable the scaling option in the IP configuration menu.
Changing the value to 0,1,2 on register 230 outputs the layer as zoomed into 1x/2x/4x, but the layer is cropped to the original size. So, you need to change the overlay width and height accordingly.
Edit: Sorry, it was my mistake. I was cropping the image to see the logo area only, it was not cropping itself