😆
Longan Nano の使い方
概要
SDカードに映像データを書き込んで、Type-Cによる給電で見れるようにする。
注意点
0:03:38:09
10:fps
160x80pxで制作
短くてもいいが映像が止まってしまうことがある。
ループにするには、最後黒で終わること
コマンドプロンプトのメモ
実行するPythonのデータなどは同じ階層にする
1.出力(mac ターミナル)
mp4の動画で行った場合
ffmpeg -i /Users/XXXXX/Desktop/XXXXX/test.mp4 -vf "fps=30" -q:v 2 /Users/XXXXX/Desktop/XXXXX/output_bmp/%d.bmp
1.出力
ffmpeg -i C:\Users\XXXXX\Desktop\Test\test.mov -vcodec bmp C:\Users\XXXXX\Desktop\Test\output_bmp%01d.bmp
2.移動
cd C:\Users\XXXXX\Desktop\Test\output_bmp
.移動先でpythonを実行させる
bmp2hex.pyも使うので同じフォルダに入れる
#!/usr/bin/env python
##@file bmp2hex.py
# @ingroup util
# A script for converting a 1-bit bitmap to HEX for use in an Arduino sketch.
#
# The BMP format is well publicized. The byte order of the actual bitmap is a
# little unusual. The image is stored bottom to top, left to right. In addition,
# The pixel rows are rounded to DWORDS which are 4 bytes long. SO, to convert this
# to left to right, top to bottom, no byte padding. We have to do some calculations
# as we loop through the rows and bytes of the image. See below for more
#
# Usage:
# >>>bmp2hex.py [-i] [-r] [-n] [-d] [-x] [-w <bytes>] [-b <size-bytes>] <infile> <tablename>
#
# @param infile The file to convert.
# @param tablename The name of the table to create
# @param raw "-r", bitmap written as raw table [optional]
# @param invert "-i", to invert image pixel colors [optional]
# @param tablewidth "-w <bytes>, The number of characters for each row of the output table [optional]
# @param sizebytes "-b <bytes>, Bytes = 0, 1, or 2. 0 = auto. 1 = 1-byte for sizes. 2 = 2-byte sizes (big endian) [optional]
# @param named "-n", use a names structure [optional]
# @param double "-d", use double bytes rather than single ones [optional]
# @param xbm "-x", use XBM format (bits reversed in byte) [optional]
# @param version "-v", returns version number
#
# @author Robert Gallup 2016-02
#
# Author: Robert Gallup (bg@robertgallup.com)
# License: MIT Opensource License
#
# Copyright 2016-2018 Robert Gallup
#
import sys, array, os, textwrap, math, random, argparse
class DEFAULTS(object):
STRUCTURE_NAME = 'GFXMeta'
VERSION = '2.3'
def main ():
# Default parameters
infile = ""
tablename = ""
tablewidth = 16
sizebytes = 0
invert = False
raw = False
named = False
double = False
xbm = False
version = False
k210 = False
k210bin = False
change = False
# Set up parser and handle arguments
parser = argparse.ArgumentParser()
# parser.add_argument ("infile", help="The BMP file(s) to convert", type=argparse.FileType('r'), nargs='+', default=['-'])
parser.add_argument ("infile", help="The BMP file(s) to convert", type=argparse.FileType('r'), nargs='*', default=['-'])
parser.add_argument ("-r", "--raw", help="Outputs all data in raw table format", action="store_true")
parser.add_argument ("-k", "--k210", help="Outputs as K210 AI RGB format", action="store_true")
parser.add_argument ("-kbin", "--k210bin", help="Outputs as K210 RGB565 (pix swap) format", action="store_true")
parser.add_argument ("-c", "--change", help="change color depth", action="store_true")
parser.add_argument ("-i", "--invert", help="Inverts bitmap pixels", action="store_true")
parser.add_argument ("-w", "--width", help="Output table width in hex bytes [default: 16]", type=int)
parser.add_argument ("-b", "--bytes", help="Byte width of BMP sizes: 0=auto, 1, or 2 (big endian) [default: 0]", type=int)
parser.add_argument ("-n", "--named", help="Uses named structure (" + DEFAULTS.STRUCTURE_NAME + ") for data", action="store_true")
parser.add_argument ("-d", "--double", help="Defines data in 'words' rather than bytes", action="store_true")
parser.add_argument ("-x", "--xbm", help="Uses XBM bit order (low order bit is first pixel of byte)", action="store_true")
parser.add_argument ("-v", "--version", help="Returns the current bmp2hex version", action="store_true")
args = parser.parse_args()
# Required arguments
infile = args.infile
# Options
if args.raw:
raw = args.raw
if args.invert:
invert = args.invert
if args.width:
tablewidth = args.width
if args.bytes:
sizebytes = args.bytes % 3
if args.named:
named = args.named
if args.double:
double = args.double
if args.xbm:
xbm = args.xbm
if args.version:
print ('// bmp2hex version ' + DEFAULTS.VERSION)
if args.k210:
k210 = args.k210
if args.k210bin:
k210bin = args.k210bin
if args.change:
change = args.change
# Output named structure, if requested
if (named):
print ('struct ' + DEFAULTS.STRUCTURE_NAME + ' {')
print (' unsigned int width;')
print (' unsigned int height;')
print (' unsigned int bitDepth;')
print (' int baseline;')
print (' ' + ('uint8_t *', 'uint16_t *')[double] + 'pixel_data;')
print ('};')
print ('')
# Do the work
for f in args.infile:
if f == '-':
sys.exit()
bmp2hex(f.name, tablewidth, sizebytes, invert, raw, named, double, xbm, k210, k210bin, change)
# Utility function. Return a long int from array (little endian)
def getLONG(a, n):
return (a[n+3] * (2**24)) + (a[n+2] * (2**16)) + (a[n+1] * (2**8)) + (a[n])
# Utility function. Return an int from array (little endian)
def getINT(a, n):
return ((a[n+1] * (2**8)) + (a[n]))
# Reverses pixels in byte
def reflect(a):
r = 0
for i in range(8):
r <<= 1
r |= (a & 0x01)
a >>= 1
return (r)
# Main conversion function
def bmp2hex(infile, tablewidth, sizebytes, invert, raw, named, double, xbm, k210, k210bin, change):
# Set the table name to the uppercase root of the file name
tablename = os.path.splitext(infile)[0].upper()
# Convert tablewidth to characters from hex bytes
tablewidth = int(tablewidth) * 6
# Initilize output buffer
outstring = ''
outR = ''
outG = ''
outB = ''
# Open File
fin = open(os.path.expanduser(infile), "rb")
uint8_tstoread = os.path.getsize(os.path.expanduser(infile))
valuesfromfile = array.array('B')
try:
valuesfromfile.fromfile(fin, uint8_tstoread)
finally:
fin.close()
# Get bytes from file
values=valuesfromfile.tolist()
# Exit if it's not a Windows BMP
if ((values[0] != 0x42) or (values[1] != 0x4D)):
sys.exit ("Error: Unsupported BMP format. Make sure your file is a Windows BMP.")
# Calculate width, heigth
dataOffset = getLONG(values, 10) # Offset to image data
pixelWidth = getLONG(values, 18) # Width of image
pixelHeight = getLONG(values, 22) # Height of image
bitDepth = getINT (values, 28) # Bits per pixel
dataSize = getLONG(values, 34) # Size of raw data
# Calculate line width in bytes and padded byte width (each row is padded to 4-byte multiples)
byteWidth = int(math.ceil(float(pixelWidth * bitDepth)/8.0))
paddedWidth = int(math.ceil(float(byteWidth)/4.0)*4.0)
# For auto (sizebytes = 0), set sizebytes to 1 or 2, depending on size of the bitmap
if (sizebytes==0):
if (pixelWidth>255) or (pixelHeight>255):
sizebytes = 2
sizebytes = 2
else:
sizebytes = 1
# The invert byte is set based on the invert command line flag (but, the logic is reversed for 1-bit files)
invertbyte = 0xFF if invert else 0x00
if (bitDepth == 1):
invertbyte = invertbyte ^ 0xFF
# Output the hex table declaration
# Format depending on "raw" flag
if k210:
print("const unsigned char gImage_image[] __attribute__((aligned(128))) ={")
elif k210bin:
#RGB565 bin, swap pixel
k210bin = True #dummy
elif change:
print("P3\r\n%d %d\r\n255\r\n"%(pixelWidth, pixelHeight))
else:
if (raw):
print ('PROGMEM unsigned char const ' + tablename + ' [] = {')
if (not (sizebytes%2)):
print ("{0:#04X}".format((pixelWidth>>8) & 0xFF) + ", " + "{0:#04X}".format(pixelWidth & 0xFF) + ", " + \
"{0:#04X}".format((pixelHeight>>8) & 0xFF) + ", " + "{0:#04X}".format(pixelHeight & 0xFF) + ",")
else:
print ("{0:#04X}".format(pixelWidth & 0xFF) + ", " + "{0:#04X}".format(pixelHeight & 0xFF) + ",")
elif (named):
print ('PROGMEM ' + 'uint8_t const ' + tablename + '_PIXELS[] = {')
elif (xbm):
print ('#define ' + tablename + '_width ' + str(pixelWidth))
print ('#define ' + tablename + '_height ' + str(pixelHeight))
print ('PROGMEM uint8_t const ' + tablename + '_bits[] = {')
else:
print ('PROGMEM const struct {')
print (' unsigned int width;')
print (' unsigned int height;')
print (' unsigned int bitDepth;')
print (' uint8_t pixel_data[{0}];'.format(byteWidth * pixelHeight))
print ('} ' + tablename + ' = {')
print ('{0}, {1}, {2}, {{'.format(pixelWidth, pixelHeight, bitDepth))
# Generate HEX bytes for pixel data in output buffer
try:
if k210bin:
if (byteWidth//3)%2 != 0:
raise Exception("Invalid width!")
file = open('bmp.bin','ab')
for i in range(pixelHeight):
for j in range (byteWidth//6):
ndx = dataOffset + ((pixelHeight-1-i) * paddedWidth) + j*6
pix0_b = values[ndx+0] ^ invertbyte
pix0_g = values[ndx+1] ^ invertbyte
pix0_r = values[ndx+2] ^ invertbyte
pix1_b = values[ndx+3] ^ invertbyte
pix1_g = values[ndx+4] ^ invertbyte
pix1_r = values[ndx+5] ^ invertbyte
pix0 = (pix0_b>>3)|((pix0_g>>2)<<5)|((pix0_r>>3)<<(5+6))
pix1 = (pix1_b>>3)|((pix1_g>>2)<<5)|((pix1_r>>3)<<(5+6))
b0 = pix0&0xff;
b1 = pix0>>8;
b2 = pix1&0xff;
b3 = pix1>>8;
bs = bytes([b1, b0, b3, b2])
# bs = bytes([b0, b1, b2, b3])
# v = values[ndx] ^ invertbyte
# if (xbm):
# v = reflect(v)
# # print ("{0:#04x}".format(v))
# # outstring += "{0:#04x}".format(v) + ", "
# bs = bytes(v)
#print("%x %x,"%(pix0,pix1))
#print("%x %x %x %x"%(pix1&0xff, pix1>>8, pix0&0xff, pix0>>8))
#print("%c%c%c%c"%(pix1&0xff, pix1>>8, pix0&0xff, pix0>>8))
#tmp = struct.pack('BBBB',)
file.write(bs)
file.close()
exit(0)
elif change:
for i in range(pixelHeight):
for j in range (pixelWidth):
ndx = dataOffset + ((pixelHeight-1-i) * paddedWidth) + j*3
b = (values[ndx+0]>>4)<<4
g = (values[ndx+1]>>3)<<3
r = (values[ndx+2]>>4)<<4
print("%d %d %d"%(r,g,b))
print("\r\n")
else:
for i in range(pixelHeight):
for j in range (byteWidth):
ndx = dataOffset + ((pixelHeight-1-i) * paddedWidth) + j
v = values[ndx] ^ invertbyte
if (xbm):
v = reflect(v)
# print ("{0:#04x}".format(v))
outstring += "{0:#04x}".format(v) + ", "
if (j%3 == 0): #B
outB += "{0:#04x}".format(v) + ", "
elif (j%3 == 1): #G
outG += "{0:#04x}".format(v) + ", "
else: #R
outR += "{0:#04x}".format(v) + ", "
# Wrap the output buffer. Print. Then, finish.
finally:
outstring = textwrap.fill(outstring[:-2], tablewidth)
outR = textwrap.fill(outR[:-1], tablewidth)
outG = textwrap.fill(outG[:-1], tablewidth)
outB = textwrap.fill(outB[:-1], tablewidth)
if k210:
print (" //R")
print (outR)
print (" //G")
print (outG)
print (" //B")
print (outB)
else:
print (outstring)
if k210:
print ('};')
else:
if (named):
print ('};')
print (DEFAULTS.STRUCTURE_NAME + ' const ' + tablename + ' = {{{0}, {1}, {2}, 0, '.format(pixelWidth, pixelHeight, bitDepth) + \
('(uint8_t *)', '(uint16_t *)')[double] + tablename + "_PIXELS};\n\n")
else:
if (not (raw or xbm)):
print (".",end = "")
# print ("};")
# Only run if launched from commandline
if __name__ == '__main__': main()
書き出ししたデータなどをリネームする場合
(ごくたまにリネームした時に連番が崩れてしまうことがある。)
Python rename.py
import os
dirname = '.'
fileAllName = os.listdir('.')
num = 0
for name in fileAllName:
print(name)
if name.endswith(".bmp"):
newname = str(num) + ".bmp"
print(newname),
num += 1
os.rename(name,newname);
書き出し
Python genhex.py
(そのまえに中のwhile num <= 150:をフレーム数にあわせる)
import os
if os.path.exists('bmp.bin'):
os.remove('bmp.bin')
num = 0
while num <= 150:
#macの場合はpython.exeをpython3に書き換え
os.system("python.exe bmp2hex.py -kbin {0}.bmp".format(num))
num += 1
4.binをSDに入れて完成
参考
Discussion