Created
February 18, 2015 16:07
-
-
Save mxwell/a514998e6687e8bd9871 to your computer and use it in GitHub Desktop.
Script to extract a picture from a BT.656 frame
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#! /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() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Great job, I will try it in my project and will give you feed back
Thank you