Skip to content

Instantly share code, notes, and snippets.

@mxwell
Created February 18, 2015 16:07
Show Gist options
  • Save mxwell/a514998e6687e8bd9871 to your computer and use it in GitHub Desktop.
Save mxwell/a514998e6687e8bd9871 to your computer and use it in GitHub Desktop.
Script to extract a picture from a BT.656 frame
#! /usr/bin/python
###############################################################################
# Script converts a single frame, compliant with ITU-R BT.656-5,
# into a picture of given format (like PNG, JPEG, BMP, etc)
#
# Tested with Python 2.7.5, Pillow 2.7
###############################################################################
from PIL import Image
import sys
THE_FIRST_LINE_ON_TOP = False
LINES, ACTIVE_LINES, TOTAL_SAMPLES = 625, 576, 864
ACTIVE_SAMPLES = 720
def is_active(line):
return not(line < 23 or (311 <= line < 336) or (624 <= line))
# equations are from http://en.wikipedia.org/wiki/YCbCr#ITU-R_BT.601_conversion
def ycbcr_to_rgb(luma, chroma_blue, chroma_red):
luma_m = 298.082 * luma
red = (luma_m + 408.583 * chroma_red) / 256 - 222.921
green = (luma_m - 100.291 * chroma_blue - 208.120 * chroma_red) / 256 + 135.576
blue = (luma_m + 516.412 * chroma_blue) / 256 - 276.836
return int(red), int(green), int(blue)
def convert_to_picture(frame):
# group bytes into lines
line_length = TOTAL_SAMPLES * 2
offset = (TOTAL_SAMPLES - ACTIVE_SAMPLES) * 2
frame = [frame[i:i + line_length] for i in range(offset, len(frame), line_length)]
# list of active lines
active = [line for line in range(1, LINES + 1) if is_active(line)]
half = len(active) / 2
if THE_FIRST_LINE_ON_TOP:
ordered_lines = [x for sub in zip(active[0:half], active[half:]) for x in sub]
else:
ordered_lines = [x for sub in zip(active[half:], active[0:half]) for x in sub]
image = Image.new('RGB', (ACTIVE_SAMPLES, ACTIVE_LINES))
for i, line in enumerate(ordered_lines):
samples = [int(sample) for sample in frame[line]]
for j in range(0, ACTIVE_SAMPLES, 2):
chroma_blue, luma0, chroma_red, luma1 = samples[j * 2:j * 2 + 4]
image.putpixel((j, i), ycbcr_to_rgb(luma0, chroma_blue, chroma_red))
image.putpixel((j + 1, i), ycbcr_to_rgb(luma1, chroma_blue, chroma_red))
return image
def main():
if len(sys.argv) < 3:
print "Usage: %s <frame> <output with extension>" % sys.argv[0]
exit(0)
frame = []
try:
frame_file = open(sys.argv[1], 'rt')
frame = frame_file.readlines()
frame_file.close()
except IOError:
print 'Cannot open frame file'
exit(1)
if len(frame) != LINES * TOTAL_SAMPLES * 2:
print("Wrong size of frame: actual size - %d value(s), expected %d values" %
(len(frame), LINES * TOTAL_SAMPLES * 2))
exit(1)
image = convert_to_picture(frame)
print "Frame converted"
try:
image.save(sys.argv[2])
except KeyError:
print "Error: Cannot decide on picture format"
exit(1)
except IOError:
print "Error: Cannot save output"
exit(1)
print "Written to %s" % sys.argv[2]
if __name__ == '__main__':
main()
@ABADY1000
Copy link

Great job, I will try it in my project and will give you feed back

Thank you

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment