Raspberry Pi 驱动5110播放Bad Apple

如何使用树莓派驱动Nokia5110 LCD在之前已经提及,还是使用adafruit的驱动方案。

这里不得不提的是在Raspbmc中是无法使用Hardware SPI的,在装了Raspbian后,终于用上了Hardware SPI,刷新速度一下子上去了,但是有一个bug还是存在的,就是第一次运行没显示,需要运行其他的py程序之后才能在5110上显示画面。。。。

具体方法
由于该方案本身就可以显示图片文字等等,所以思路也就是让它不断显示图片罢了,然后再伴上音乐,就是这样。。

帧的获得
我使用了MATLAB来获取视频文件的所有帧,因为它实在是太方便了。
首先要将视频文件载入,导入为矩阵(MATLAB支持少数几种视频格式,所以如果格式不支持还得转下码)

clear;clc;
xyloObj = VideoReader('ba.mp4');
nFrames = xyloObj.NumberOfFrames;
vidHeight = xyloObj.Height;
vidWidth = xyloObj.Width;

% Preallocate movie structure.
mov(1:nFrames) = ...
    struct('cdata', zeros(vidHeight, vidWidth, 3, 'uint8'),...
           'colormap', []);

% Read one frame at a time.
for k = 1 : nFrames
    mov(k).cdata = read(xyloObj, k);
    disp(k);
end

% Size a figure based on the video's width and height.
hf = figure;
set(hf, 'position', [150 150 vidWidth vidHeight])

% Play back the movie once at the video's frame rate.
% movie(hf, mov, 1, xyloObj.FrameRate);
for I = 1 : nFrames
    %首先使用imresize将原矩阵resize成我们想要的分辨率,然后转换为灰度,其实ls得到的就是logical型的矩阵了
    ls = im2bw(imresize(mov(i).cdata, [48,84]));
    %将ls保存为bmp格式的图片
    imwrite(ls, strcat([BMP\ba', num2str(i), '.bmp]), bmp);
    %显示正在转换的帧
    disp(i);
end

2 播放功能的实现
由于是播放图片,所以要考虑到帧率,具体思路就是在播放视频前先获取当前时间轴timesta,然后做一个while死循环,不断获取当前时间轴timenow,计算已经播放了的时间time=timenow-timesta,那么要播放的帧就是time×30+1(我使用的视频是30帧/秒的),这样做的好处就是永远是声画同步的,缺点就是会掉帧。
声音的话直接使用了pygame模块来实现,也比较方便。

import time
import Adafruit_Nokia_LCD as LCD
import Adafruit_GPIO.SPI as SPI
import Image
# In order to play music
import pygame
print 'Press Ctrl-C to quit.'
# Raspberry Pi hardware SPI config:
DC = 23
RST = 24
SPI_PORT = 0
SPI_DEVICE = 0
# Hardware SPI usage:
disp = LCD.PCD8544(DC, RST, spi=SPI.SpiDev(SPI_PORT, SPI_DEVICE, max_speed_hz=4000000))
# Initialize library.
disp.begin(contrast=60)
# Clear display.
disp.clear()
disp.display()
# Play music
pygame.init()
pygame.mixer.music.load("badapple.mp3")
pygame.mixer.music.play()
# Time starting display image
timesta = time.time()
while True:
       # Time now
       timenow = time.time()
       # Calculate the frame to display
       frame = int((timenow - timesta)*30) + 1
       # Load image and convert to 1 bit color.
       image = Image.open('/home/pi/badapple/BMP/ba' + str(frame) + '.bmp).convert('1')
       disp.image(image)
       disp.display()

所有文件下载:bad apple.zip

Fibonacci弧线

先定义个function画圆弧

function arc(cen,R,ths,the)
    %cen为圆心坐标,R为边长,ths和the是起始和结束弧度
    theta=ths:-pi/50:the;
    x=R*cos(theta)+cen(1); 
    y=R*sin(theta)+cen(2); 
    plot(x,y,'-') 
    axis equal 
end

然后再来画Fibonacci弧线

function fibonacci(N)
%Fibonacci弧线
%N为迭代次数
if nargin==0
    N=5;
end
figure;
hold on;
%定义一些起始值,cen为圆心坐标
cen=[0,0];
R0=0;R1=1;R=1;
ths=0;
for i=1:N
    way = mod(i,4);
    switch way
        case 2
            cen(1)=cen(1)+R0;
            ths=1;
        case 3
            cen(2)=cen(2)-R0;
            ths=1/2;
        case 0
            cen(1)=cen(1)-R0;
            ths=0;
        case 1
            cen(2)=cen(2)+R0;
            ths=3/2;
    end
    R=R0+R1;
    R0=R1;R1=R;
    arc(cen,R,ths*pi,(ths-1/2)*pi);
end

测试下:

fibonacci(20);    %迭代20次

效果图:

fibonacci


文献:
http://baike.baidu.com/link?url=VNzjn1S_SHm0IpTIz-9k4zUIGfuMKqQQbtidp7SSJUU7BFMysKVCisvavKmOADzt

DLA分形的MATLAB仿真

直接使用MATLAB跑就是慢些,但跑百把万的粒子数目无压力,混合编程在100000点以下跑起来很快,差不多效率提升了12倍,但150000以上时明显变慢,顿时亚历山大了,估计与c的随机数有关,暂记于此吧,上一幅1000000个粒子的DLA分形图。

DLA(1000000)

function dla(n,size,r)
%DLA分形生长模型
%n为模拟粒子的数目,size为随机产生粒子的半径,宜大,r为团簇的半径
tic;
switch nargin
    case 0
        n=10000; r=5; size=512;
    case 1
        size=512; r=5;
    case 2
        r=512;
end
rmax=0;  %粒子团的最大半径
%矩阵m用于储存点的位置
m=zeros(size*2+1,size*2+1,'uint8');
m(size+1,size+1)=1;
%生成一个随机数序列
ran=single(rand(n,1)*2*pi);
t=1;
while t<n
    xp=round(cos(ran(t,1))*(rmax+r));
    yp=round(sin(ran(t,1))*(rmax+r));
    disp(t);    %显示计算的点
    %(2*rmax+r)*pi为粒子行走的最大步数,随半径增大
    %若走完步数还未接触到团簇或接触到边界,则会进入while循环重新模拟
    for step=1:int32((2*rmax+r)*pi)
        rans=rand;
        if rans<0.25
            xp=xp+1;
        elseif rans<0.50
            yp=yp+1;
        elseif rans<0.75
            xp=xp-1;
        else
            yp=yp-1;
        end
        %判断粒子是否触界,判断的话影响速率
        %if xp == size || yp == size
        %    break;
        %end
        %判断当前粒子是否接触到团簇
        if m(xp+size+2,yp+size+1)==1 || m(xp+size,yp+size+1)==1 || m(xp+size+1,yp+size+2)==1 || m(xp+size+1,yp+size)==1
            m(xp+size+1,yp+size+1)=1;
            rmax=max(sqrt(xp^2+yp^2),rmax);
            t=t+1;
            break;
        end
    end
end
%画图
colormap(gray);
image(255-255*m);
%axis off;
save(['dla(',num2str(n),').mat'],'m','size','r');
toc;
end
#include "mex.h" // 使用MEX文件必须包含的头文件
//#include<ctime>
#include<math.h>

//获取最大值
inline double max( double x , double y)
{
    if( x > y )
        return x;
    else
        return y;
}

void dla_c(int n, int size, int r, double *m)
{
    //定义团簇的生长点
    int xp = 0, yp = 0;
    *(m + (xp + size) * (size * 2 + 1) + size - yp) = 1;
    double rmax = 0;
    double ran;
    double rans;
    double pi = 3.1415926;
    int step, stepmax;
    for(int t = 1; t < n; t++)
    {
        //显示正在计算的粒子个数
        mexPrintf("%d\n", t);
        //srand(time(NULL));
        ran = double(rand() % 100);
        ran = ran / 50 * pi;
        xp = int(cos(ran) * (rmax + r) + 0.5);
        yp = int(sin(ran) * (rmax + r) + 0.5);
        //(rmax*2+r)*pi为粒子行走的最大步数,视具体模型而定
        //若走完步数还未接触到团簇,则会进入while循环重新模拟
        step = 0, stepmax = int((r + 2 * rmax) * pi);
        do
        {
            //srand(time(NULL));
            rans = rand() % 100;
            if(rans < 25)
                xp++;
            else if(rans < 50)
                yp++;
            else if(rans < 75)
                xp--;
            else
                yp--;
            step++;
            if(step == stepmax || abs(xp) >= size / 2 || abs(yp) >= size / 2)
            {
                xp = int(cos(ran) * (rmax + r) + 0.5);
                yp = int(sin(ran) * (rmax + r) + 0.5);
                step = 0;
            }
        }while(*(m + (xp + 1 + size) * (size * 2 + 1) + size - yp) == 0
                    && *(m + (xp - 1 + size) * (size * 2 + 1) + size - yp) == 0
                    && *(m + (xp + size) * (size * 2 + 1) + size - yp - 1) == 0
                    && *(m + (xp + size) * (size * 2 + 1) + size - yp + 1) == 0);
        *(m + (xp + size) * (size * 2 + 1) + size - yp) = 1;
        rmax = max(sqrt(double(xp * xp + yp * yp)), rmax);
    }
    return;
}
void mexFunction(int nlhs,mxArray *plhs[], int nrhs,const mxArray *prhs[])
{
    //m用于储存分形图形
    double *m;
    //n为粒子的数量,size为预想DLA分形图形的半径(宜大),r为随机产生的粒子与团簇间的距离
    int n, size, r;
    n = int(*(mxGetPr(prhs[0])));
    size = int(*(mxGetPr(prhs[1])));
    r = int(*(mxGetPr(prhs[2])));
    
    plhs[0] = mxCreateDoubleMatrix(2 * size + 1, 2 * size + 1, mxREAL);
    m = mxGetPr(plhs[0]);
    
    dla_c(n, size, r, m);
}