Closed rizwanishaq closed 11 months ago
Hi @rizwanishaq
Here is a simple demo. I will be glad if this script could provide some help.
#! /usr/bin/env python
# coding: utf-8
import cv2
import numpy as np
import PyNvCodec as nvc
frame_width = 640
frame_height = 480
frame_fps = 30
frame_count = 300
def cvtColor_BGR2YUV_NV12(image):
height, width = image.shape[:2]
yuv = cv2.cvtColor(image, cv2.COLOR_BGR2YUV_I420)
uuvv = yuv[height:].reshape(2, -1)
uvuv = np.transpose(uuvv, axes=(1, 0))
yuv[height:] = uvuv.reshape(-1, width)
return yuv
# create an encoder
encoder = nvc.PyNvEncoder({
"preset": "P5",
"tuning_info": "high_quality",
"profile": "high",
"codec": "h264",
"s": f"{frame_width}x{frame_height}",
"fps": str(frame_fps),
"gop": str(frame_fps),
}, gpu_id=0)
with open("output.h264", "wb") as dstfile:
for i in range(frame_count):
# generate bgr frame
bgr = np.full((frame_height, frame_width, 3), i % 256, dtype=np.uint8)
# convert bgr to nv12
nv12 = cvtColor_BGR2YUV_NV12(bgr)
# encode frame
packet = np.ndarray(shape=(0), dtype=np.uint8)
if encoder.EncodeSingleFrame(nv12, packet):
dstfile.write(bytearray(packet))
# encoder is asynchronous, so we need to flush it
packet = np.ndarray(shape=(0), dtype=np.uint8)
while encoder.FlushSinglePacket(packet):
dstfile.write(bytearray(packet))
Thanks, working.
Is there any way that we make this part
def cvtColor_BGR2YUV_NV12(image):
height, width = image.shape[:2]
yuv = cv2.cvtColor(image, cv2.COLOR_BGR2YUV_I420)
uuvv = yuv[height:].reshape(2, -1)
uvuv = np.transpose(uuvv, axes=(1, 0))
yuv[height:] = uvuv.reshape(-1, width)
return yuv
on GPU, as this is using all the CPU.
maybe this could help.
#! /usr/bin/env python
# coding: utf-8
import cv2
import numpy as np
import PyNvCodec as nvc
frame_width = 640
frame_height = 480
frame_fps = 30
frame_count = 300
class ColorConverter:
def __init__(self, width, height, gpuid):
# vpf does not support rgb_planar -> nv12, so we need the following chain:
# rgb_planar -> rgb -> yuv420 -> nv12
self.to_rgb = nvc.PySurfaceConverter(width, height, nvc.PixelFormat.RGB_PLANAR, nvc.PixelFormat.RGB, gpuid)
self.to_yuv420 = nvc.PySurfaceConverter(width, height, nvc.PixelFormat.RGB, nvc.PixelFormat.YUV420, gpuid)
self.to_nv12 = nvc.PySurfaceConverter(width, height, nvc.PixelFormat.YUV420, nvc.PixelFormat.NV12, gpuid)
self.context = nvc.ColorspaceConversionContext(nvc.ColorSpace.BT_601, nvc.ColorRange.MPEG)
self.uploader = nvc.PyFrameUploader(width, height, nvc.PixelFormat.RGB_PLANAR, gpuid)
def convert(self, image):
# convert opencv-style image to rgb_planar
image = image[:, :, ::-1].transpose((2, 0, 1))
image = np.ascontiguousarray(image)
# copy data: cpu -> gpu
surface = self.uploader.UploadSingleFrame(image)
if surface.Empty(): return None
# do actual convertions
surface = self.to_rgb.Execute(surface, self.context)
if surface.Empty(): return None
surface = self.to_yuv420.Execute(surface, self.context)
if surface.Empty(): return None
surface = self.to_nv12.Execute(surface, self.context)
if surface.Empty(): return None
return surface
encoder = nvc.PyNvEncoder({
"preset": "P5",
"tuning_info": "high_quality",
"profile": "high",
"codec": "h264",
"s": f"{frame_width}x{frame_height}",
"fps": str(frame_fps),
"gop": str(frame_fps),
}, gpu_id=0)
converter = ColorConverter(frame_width, frame_height, 0)
with open("output.h264", "wb") as dstfile:
for i in range(frame_count):
# generate bgr frame
bgr = np.full((frame_height, frame_width, 3), i % 256, dtype=np.uint8)
# convert bgr(cpu) to nv12(gpu)
nv12 = converter.convert(bgr)
# encode frame, using: EncodeSingleSurface
packet = np.ndarray(shape=(0), dtype=np.uint8)
if encoder.EncodeSingleSurface(nv12, packet):
dstfile.write(packet.data)
# encoder is asynchronous, so we need to flush it
packet = np.ndarray(shape=(0), dtype=np.uint8)
while encoder.FlushSinglePacket(packet):
dstfile.write(packet.data)
yes, it is now working on GPU, thanks.
"Is it possible to generate H.264 encoded frames, feed them back into a decoder, and then convert them back to cv2 images for testing purposes?"
Hi @rizwanishaq
Please check out https://github.com/RomanArzumanyan/VALI. It’s a VPF successor which is actively developed and maintained. It has compatible API and module naming.
WRT you question - yes, it’s possible. Please check out SampleMeasureVideoQuality
in VPF repository or VALI tests.
Is there any example where we can convert OpenCV image np.array() to h264 encoding?