寒假期间,一起做了一款pc端的美颜相机,在交流会期间,看到有的同学做了一些非常牛的功能添加,心血来潮,想整个视频运动追踪识别,在这和大家分析一下算法思路
1、原理很简单,就是在视频中的物体,就可以通过得到前后两张图片提供的二维数组之差,当两者之前的差值超过一个数,前后相差过大的时候,我们通过画笔去把他画出来,就可以得到我们想要的结果。
2、之前第一步遇到的问题,就是如何得到第一张图的数据,并且去和第二张图进行对比,在这里的话,我的思路是用一个数组去存储通过摄像头获取到底第一张图片,并且通过BufferedImage来缓存图片,然后重新定义一个数组缓存第二张图片的数据,就可以进行处理后的数据啦
3、代码如下(菜单栏的一些功能代码尚未给出,这里仅仅给出运动追踪识别的代码)
a.窗体界面
public class CameraUI {
public void draw(){
JFrame jFrame=new JFrame();
jFrame.setTitle("视频运动追踪识别");
jFrame.setSize(800,900);
jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jFrame.setLocationRelativeTo(null);
BorderLayout borderLayout=new BorderLayout();
jFrame.setLayout(borderLayout);
JPanel cennter=new JPanel();
cennter.setBackground(Color.cyan);
jFrame.add(cennter,BorderLayout.CENTER);
//菜单栏以及相关功能的实现
//开始定义菜单,菜单栏以及相关按钮
JMenuBar jMenuBar=new JMenuBar();
jFrame.add(jMenuBar,BorderLayout.NORTH);
//监听器的设置
CameraMouse cameraMouse=new CameraMouse();
//定义在菜单栏中的菜单选项
String[]name1={"运动追踪","视频","图片","拍照","特殊滤镜","编辑","帮助"};
//开辟一个menu数组来存储调用与添加
JMenu[]menu=new JMenu[name1.length];
for (int i=0;i< name1.length;i++) {
JMenu jMenu = new JMenu(name1[i]);
menu[i]=jMenu;
jMenuBar.add(jMenu);
}
//子菜单中的菜单选项
String[]name={"打开","关闭","退出"};
for (int i=0;i<name.length;i++) {
JMenuItem jMenuItem = new JMenuItem(name[i]);
jMenuItem.addActionListener(cameraMouse);
menu[0].add(jMenuItem);
}
//可视一定要在画笔前
jFrame.setVisible(true);
cameraMouse.graphicsmouse=cennter.getGraphics();
}
public static void main(String[] args) {
CameraUI cameraUI=new CameraUI();
cameraUI.draw();
}
}
b.监听器以及线程控制
public class CameraMouse implements ActionListener {
//获取点击按钮的名字
public String name;
//获取画笔
public Graphics graphicsmouse;
//创造线程的对象进行调用
public CameraThread cameraThread;
public void actionPerformed(ActionEvent e){
String name=e.getActionCommand();
System.out.println("正在点击的操作是:"+name);
if ("打开".equals(name)){
if (cameraThread==null){
cameraThread=new CameraThread(graphicsmouse);
//开始启动线程
cameraThread.start();
}
}else if ("关闭".equals(name)){
cameraThread.flag=false;
}
}
}
c.运动追踪方法实现以及相关线程代码
public class CameraThread extends Thread{
//开关控制线程
public boolean flag=true;
//画笔初始化
public Graphics graphicsthread;
//方法构造传送画笔
public CameraThread(Graphics graphicsthread){
this.graphicsthread=graphicsthread;
}
//线程的书写和使用
public void run(){
//摄像头的调动
Webcam webcam=Webcam.getDefault();
webcam.open();
System.out.println("启动线程.."+this.getName());
//利用while循环来使用线程,线程只能运行一次,结束后的线程不能重新调用
while (flag) {
//获取摄像头拍到的数据
BufferedImage bufferedImage1 = webcam.getImage();
//用数组存储下来,获取第一张图片
int[][]pixel1Arr=getImagePixel(bufferedImage1);
//创建缓冲图片
BufferedImage buffer=new BufferedImage(bufferedImage1.getWidth(),bufferedImage1.getHeight(),BufferedImage.TYPE_INT_BGR);
//获取缓存区的画笔
Graphics grabuffer=buffer.getGraphics();
//获取摄像头拍到的数据,重新获取
BufferedImage bufferedImage2 = webcam.getImage();
//用数组存储下来,存储的目的就是与第一张已经缓存下来的图片做对比,
int[][]pixel2Arr=getImagePixel(bufferedImage2);
//遍历第二张图片的数组
for (int i=0;i<pixel2Arr.length;i++){
for (int j=0;j<pixel2Arr[0].length;j++){
//第二张图片的像素
int pixel2=pixel2Arr[i][j];
if ((null!=pixel2Arr)){
// 转成Color对象,设置给画笔,画出像素点
Color rc=new Color(pixel2);
Color pixel1=new Color(pixel1Arr[i][j]);
//前后相互比较,这里是取的G值做的差
int diff=Math.abs(rc.getGreen()- pixel1.getGreen());
if ((diff)>30) {
grabuffer.setColor(Color.white);
grabuffer.fillOval(i, j, 2, 2);
} else if (diff<30) {
grabuffer.setColor(Color.black);
grabuffer.fillOval(i, j, 2, 2);
}
}
}
}
//把拍到的数据画出来
graphicsthread.drawImage(buffer, 100, 100,600,600, null);
}
System.out.println("结束线程");
}
//数据存储
public int[][] getImagePixel(BufferedImage buffImage) {
int w = buffImage.getWidth();
int h = buffImage.getHeight();
int[][] pixelArr = new int[w][h];
// 获取图片中的每一个像素值保存到二维数组中
for (int i = 0; i < w; i++) {
for (int j = 0; j < h; j++) {
int pixel = buffImage.getRGB(i, j);
pixelArr[i][j] = pixel;
}
}
return pixelArr;
}
}
4.视频效果图不方便截图,感兴趣的小伙伴来call我
版权归原作者 网友小浩 所有, 如有侵权,请联系我们删除。