最近夭折了一个项目,由于我预研失败,同时我将被惩罚,被外派去其他公司干活,干完再回来。
下面来说说这个项目。最后再总结为什么失败。
基于red5的视频聊天,桌面共享。下图是简单的逻辑图

做视频聊天,做桌面共享,而且要在手机端也能显示出来,因此采用red5 这个开源的流媒体服务器。
公司的产品是典型的基于服务的多客户端模式。
简单的说是一个java后台发布服务,客户端有windows桌面版(java);mac桌面(java);android;ios,由于是自动化办公,所以集成了im,office,网盘等等功能。
下面看看怎么玩的。
1 dsj 这是微软的dictShow的java 版,免费使用,非开源
下载下来以后里面有个dsj.dll放如c盘 system32里面。
【简单调用本地摄像头】
package com.oatos.red5; /** dsj demo code. You may use, modify and redistribute this code under the terms laid out in the header of the DSJDemo application. copyright 2009 N.Peters humatic GmbH Berlin, Germany **/ import de.humatic.dsj.*; import javax.swing.*; /** Updated for 0_8_6 Demonstrates changing formats delivered by a capture device before and after the filtergraph is built. Configuration before building the graph is done via a ready made dialog, whose source-code can be found in the main dsj demo. dsj 0_8_51 adds some missing functionality to address single output pins on capture devices with separate capture and preview pins. This makes things a little more complex, but finally also takes hardware reality into account after the graph is built. 0_8_6 intoduces the setCropSize method, which enables fine grain control of output sizes with devices, that otherwise only offer limited choice of dimensions with their supported formats. This mostly applies to the more professional capture boards and cameras. For example Viewcast Osprey boards or IDS Ueye cameras will only have one dimension to select from, but then can shrink and / or crop from that. There is no clear standard, so the implementation is driver specific. Also new in 0_8_6 are api methods to configure analog video digitizers. **/ public class MyCaptureFormats implements java.beans.PropertyChangeListener { private DSCapture graph; private DSCapture.CaptureDevice vDev; private DSFilter.DSPin activeOut, previewOut, captureOut; private DSMediaType [] mf; private JFrame f, imageFrame; private JComboBox formatSelector; private JSpinner fpsSpinner; int FORMAT_INDEX = 1; boolean changingFormat, flip; private String[] tvFormatStr = new String[]{"ATV_None", "ATV_NTSC_M", "ATV_NTSC_M_J", "ATV_NTSC_433", "", "ATV_PAL_B", "ATV_PAL_D", "", "ATV_PAL_H", "ATV_PAL_I", "ATV_PAL_M", "ATV_PAL_N", "ATV_PAL_60", "ATV_SECAM_B", "ATV_SECAM_D", "ATV_SECAM_G", "ATV_SECAM_H", "ATV_SECAM_K ", "ATV_SECAM_K1", "ATV_SECAM_L", "ATV_SECAM_L1", "ATV_PAL_N_COMBO"}; public MyCaptureFormats() {} public void createGraph() { f = new JFrame("dsj - CaptureFormats, 0_8_6"); //graph = DSCapture.fromUserDialog(f, DSFiltergraph.DD7, this); DSFilterInfo[][] dsi = DSCapture.queryDevices(); /** this sample only uses video **/ graph = new DSCapture(DSFiltergraph.DD7, dsi[0][0], false, DSFilterInfo.doNotRender(), this); f.add(java.awt.BorderLayout.CENTER, graph.asComponent()); vDev = graph.getActiveVideoDevice(); previewOut = vDev.getDeviceOutput(DSCapture.CaptureDevice.PIN_CATEGORY_PREVIEW); captureOut = vDev.getDeviceOutput(DSCapture.CaptureDevice.PIN_CATEGORY_CAPTURE); /** We're only interested in the preview output for this demo, but a lot of devices (webcams amongst others) do not have a separate preview pin (preview is then built via a Tee filter) **/ activeOut = previewOut != null ? previewOut : captureOut; int pinIndex = activeOut.getIndex(); DSFilterInfo.DSPinInfo usedPinInfo = vDev.getFilterInfo().getDownstreamPins()[pinIndex]; formatSelector = new JComboBox(); formatSelector.setLightWeightPopupEnabled(false); mf = usedPinInfo.getFormats(); for (int i = 0; i < mf.length; i++) { formatSelector.addItem(mf[i].getDisplayString()); } int currentFormat = vDev.getSelectedFormat(activeOut); try{ formatSelector.setSelectedIndex(currentFormat); } catch (Exception iae){ } formatSelector.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent e) { if (changingFormat) return; try{ changingFormat = true; vDev.setOutputFormat(activeOut, formatSelector.getSelectedIndex()); } catch (Exception ex){ex.printStackTrace();} } }); try{ DSFilterInfo.DSMediaFormat dsmf = (DSFilterInfo.DSMediaFormat)(mf[currentFormat]); fpsSpinner = new JSpinner(new SpinnerNumberModel( (int)(previewOut != null ? vDev.getFrameRate(previewOut) : vDev.getFrameRate(captureOut)), (int)(dsmf.getFrameRateRange()[0])-5, (int)(dsmf.getFrameRateRange()[1])+5, 5)); } catch (Exception e){ fpsSpinner = new JSpinner(new SpinnerNumberModel(15, 0, 30, 5)); } fpsSpinner.addChangeListener(new javax.swing.event.ChangeListener() { public void stateChanged(javax.swing.event.ChangeEvent ce){ if (changingFormat) return; try{ vDev.setFrameRate(activeOut, Float.parseFloat(fpsSpinner.getValue().toString())); System.out.println((previewOut != null ? "preview" : "capture")+" fps: "+vDev.getFrameRate(activeOut)); } catch (Exception e){ System.out.println(e.toString()); } } }); /** You can take the short way home and change things with a user dialog. See the SwingPropPage sample for a way to make this more java-like. **/ final JButton fd = new JButton("WDM dialog"); fd.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent e) { changingFormat = true; int result = graph.getActiveVideoDevice().showDialog(DSCapture.CaptureDevice.WDM_PREVIEW); if (result < 0) { System.out.println("cant show preview dialog: "+result); result = graph.getActiveVideoDevice().showDialog(DSCapture.CaptureDevice.WDM_CAPTURE); } if (result < 0) { System.out.println("no capture dialog either: "+result); result = graph.getActiveVideoDevice().showDialog(DSCapture.CaptureDevice.WDM_DEVICE); } if (result < 0) changingFormat = false; } }); JPanel ctrls = new JPanel(); ctrls.add(new JLabel("Setting format on pin: "+(previewOut != null ? previewOut.getName() : captureOut.getName())+" ")); ctrls.add(formatSelector); ctrls.add(new JLabel(" fps: ")); ctrls.add(fpsSpinner); ctrls.add(fd); //f.add(java.awt.BorderLayout.NORTH, ctrls); final JCheckBox continous = new JCheckBox("grab continously"); final JButton gi = new JButton("拍照"); gi.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent e) { /** The grabbed frame will always be 24bit BGR unless the graph is built with the YUV flag set. In that case getImage() will return null, but YUV data is available via getData(). Requires a YUV source of course. **/ java.awt.image.BufferedImage bi = graph.getImage(); final JLabel imgLabel = new JLabel(new ImageIcon(bi)); //final java.awt.image.WritableRaster raster = bi.getWritableTile(bi.getWidth(), bi.getHeight()); //byte[] imgData = ((java.awt.image.DataBufferByte)raster.getDataBuffer()).getData(); try{ imageFrame.dispose(); } catch (NullPointerException ne){} imageFrame = new JFrame("dsj captured frame"); imageFrame.add(java.awt.BorderLayout.CENTER, imgLabel); JTextArea ta = new JTextArea(bi.toString(), 5, 1); ta.setLineWrap(true); imageFrame.add(java.awt.BorderLayout.SOUTH, ta); imageFrame.setPreferredSize(new java.awt.Dimension(bi.getWidth()+100, bi.getHeight()+200)); imageFrame.pack(); imageFrame.setLocation(600, 200); imageFrame.setVisible(true); if (!continous.isSelected()) return; Runnable r = new Runnable() { public void run(){ while(imageFrame.isVisible()) { try{ graph.getImage(); imgLabel.updateUI(); Thread.sleep(40); } catch (Exception e){} } } }; new Thread(r).start(); } }); final JPanel lowerCtrls = new JPanel(new java.awt.GridLayout(2,3)); lowerCtrls.setBorder(new javax.swing.border.EmptyBorder(5,5,5,5)); ((java.awt.GridLayout)(lowerCtrls.getLayout())).setVgap(5); ((java.awt.GridLayout)(lowerCtrls.getLayout())).setHgap(5); final JPanel cropCoords = new JPanel(new java.awt.GridLayout(1,4)); final int[] coords = new int[]{0, 0, (int)(graph.getMediaDimension().getWidth()), (int)(graph.getMediaDimension().getHeight())}; for (int i = 0; i < 4; i++) { final JTextField ct = new JTextField(String.valueOf(coords[i])); ct.setPreferredSize(new java.awt.Dimension(30, 22)); cropCoords.add(ct); } final JButton crop = new JButton("crop/size image"); crop.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent e) { int[] caps = activeOut.getFormatCaps(); for (int i = 0; i < 4; i++) coords[i] = Integer.valueOf(((JTextField)cropCoords.getComponent(i)).getText().trim()).intValue(); changingFormat = true; graph.getActiveVideoDevice().setCropSize(activeOut, coords[0], coords[1], coords[2], coords[3]); } }); JPanel fl = new JPanel(new java.awt.GridLayout(1,3)); final JCheckBox hor = new JCheckBox("左反转"); final JCheckBox ver = new JCheckBox("上反转"); final JButton flip = new JButton("反转"); flip.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent e) { boolean flipGrabbedImage = true; int fli = (hor.isSelected() ? 2 : 0) | (ver.isSelected() ? 1 : 0) | (flipGrabbedImage ? 4 : 0); graph.flipImage(fli); } }); fl.add(hor); fl.add(ver); fl.add(flip); final javax.swing.JComboBox tvf = new javax.swing.JComboBox(tvFormatStr); try{ final int[] vdi = ((DSCapture)graph).getActiveVideoDevice().getVDigSettings(); int fIdx = 0; while ((vdi[0] >>= 1) != 0) { fIdx++; } tvf.setSelectedIndex(fIdx+1); tvf.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent e) { if ((vdi[2] & (1 << (tvf.getSelectedIndex() - 1))) != 0) graph.getActiveVideoDevice().configureVDig((1 << (tvf.getSelectedIndex() - 1)), 3); else System.out.println("not supported"); } }); } catch (Exception e){ System.out.println("Can't get / set TVFormat with this device: "+e.toString()); tvf.setEnabled(false); } //lowerCtrls.add(cropCoords); lowerCtrls.add(fl); lowerCtrls.add(gi); //lowerCtrls.add(crop); //lowerCtrls.add(tvf); //lowerCtrls.add(continous); f.add(java.awt.BorderLayout.SOUTH, lowerCtrls); f.pack(); f.setVisible(true); /** Don't do this at home. This demo relies on dsj closing and disposing off filtergraphs when the JVM exits. This is OK for a "open graph, do something & exit" style demo, but real world applications should take care of calling dispose() on filtergraphs they're done with themselves. **/ f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); } public void propertyChange(java.beans.PropertyChangeEvent pe) { if (DSJUtils.getEventType(pe) == DSFiltergraph.FORMAT_CHANGED) { f.add("Center", graph.asComponent()); f.pack(); int sf = vDev.getSelectedFormat(previewOut != null ? previewOut : captureOut); formatSelector.setSelectedIndex(sf); DSFilterInfo.DSMediaFormat dsmf = (DSFilterInfo.DSMediaFormat)(mf[sf]); SpinnerNumberModel model = (SpinnerNumberModel)(fpsSpinner.getModel()); model.setMinimum((int)(dsmf.getFrameRateRange()[0])-5); model.setMaximum((int)(dsmf.getFrameRateRange()[1])+5); fpsSpinner.setModel(model); try{ float currentRate = previewOut != null ? vDev.getFrameRate(previewOut) : vDev.getFrameRate(captureOut); fpsSpinner.setValue(new Integer((int)currentRate)); } catch (Exception e){e.printStackTrace();} changingFormat = false; } } public static void main(String[] args){ new MyCaptureFormats().createGraph(); } }
2 red5-client
red5提供了2个jar ,一个是server.一个是client 用来连接red5服务器。
实例【捕获red5 demo publisher 的视频流】
首先打开red5 ->demo->publisher

点击connect,翻开video页签,选择摄像头,点击start.最后点击public

【使用代码捕获】使用上图中的streamName
package com.oatos.red5; import java.nio.ByteBuffer; import java.util.Map; import org.apache.mina.core.buffer.IoBuffer; import org.red5.client.net.rtmp.ClientExceptionHandler; import org.red5.client.net.rtmp.RTMPClient; import org.red5.io.ITag; import org.red5.io.ITagWriter; import org.red5.io.flv.impl.FLVWriter; import org.red5.io.flv.impl.Tag; import org.red5.io.utils.ObjectMap; import org.red5.server.api.event.IEvent; import org.red5.server.api.event.IEventDispatcher; import org.red5.server.api.event.IEventListener; import org.red5.server.api.service.IPendingServiceCall; import org.red5.server.api.service.IPendingServiceCallback; import org.red5.server.net.rtmp.Channel; import org.red5.server.net.rtmp.RTMPConnection; import org.red5.server.net.rtmp.codec.RTMP; import org.red5.server.net.rtmp.event.AudioData; import org.red5.server.net.rtmp.event.IRTMPEvent; import org.red5.server.net.rtmp.event.Notify; import org.red5.server.net.rtmp.event.Ping; import org.red5.server.net.rtmp.event.VideoData; import org.red5.server.net.rtmp.message.Header; import org.red5.server.net.rtmp.status.StatusCodes; import org.red5.server.stream.IStreamData; public class ClientTest extends RTMPClient { private String server = "localhost"; private int port = 1935; private String application = "oflaDemo"; // private String application = "live"; // private String filename = "prometheus.flv"; // private String filename = "NAPNAP.flv"; // private String filename = "cameraFeed"; private String filename = "stream1371547539364"; // live stream (true) or vod stream (false) private boolean live = true; private static boolean finished = false; public static void main(String[] args) throws InterruptedException { final ClientTest player = new ClientTest(); // decide whether or not the source is live or vod player.setLive(true); // connect player.connect(); synchronized (ClientTest.class) { if (!finished) ClientTest.class.wait(); } System.out.println("Ended"); } public void connect() { setExceptionHandler(new ClientExceptionHandler() { @Override public void handleException(Throwable throwable) { throwable.printStackTrace(); } }); setStreamEventDispatcher(streamEventDispatcher); connect(server, port, application, connectCallback); } private IEventDispatcher streamEventDispatcher = new IEventDispatcher() { @SuppressWarnings("unchecked") public void dispatchEvent(IEvent event) { System.out.println("ClientStream.dispachEvent()" + event.toString()); if (!(event instanceof IRTMPEvent)) { //logger.debug("skipping non rtmp event: " + event); return; } IRTMPEvent rtmpEvent = (IRTMPEvent) event; /* * if (log.isDebugEnabled()) { log.debug("rtmp event: " + * rtmpEvent.getHeader() + ", " + * rtmpEvent.getClass().getSimpleName()); } */ if (!(rtmpEvent instanceof IStreamData)) { //log.debug("skipping non stream data"); return; } if (rtmpEvent.getHeader().getSize() == 0) { //log.debug("skipping event where size == 0"); return; } ITag tag = new Tag(); tag.setDataType(rtmpEvent.getDataType()); if (rtmpEvent instanceof VideoData) { int videoTs=0; videoTs += rtmpEvent.getTimestamp(); tag.setTimestamp(videoTs); //(VideoData)rtmpEvent.getData(); } else if (rtmpEvent instanceof AudioData) { int audioTs=0; audioTs += rtmpEvent.getTimestamp(); tag.setTimestamp(audioTs); } IoBuffer data = ((IStreamData) rtmpEvent).getData() .asReadOnlyBuffer(); tag.setBodySize(data.limit()); tag.setBody(data); // log.debug(data.toString()); System.out.println(data.toString()); try { //ITagWriter writer = new FLVWriter(data, true); //writer.writeTag(tag); } catch (Exception e) { throw new RuntimeException(e); } } }; private IPendingServiceCallback connectCallback = new IPendingServiceCallback() { public void resultReceived(IPendingServiceCall call) { System.out.println("connectCallback"); ObjectMap<?, ?> map = (ObjectMap<?, ?>) call.getResult(); String code = (String) map.get("code"); if ("NetConnection.Connect.Rejected".equals(code)) { System.out.printf("Rejected: %s\n", map.get("description")); disconnect(); synchronized (ClientTest.class) { finished = true; ClientTest.class.notifyAll(); } } else if ("NetConnection.Connect.Success".equals(code)) { createStream(createStreamCallback); } else { System.out.printf("Unhandled response code: %s\n", code); } } }; private IPendingServiceCallback createStreamCallback = new IPendingServiceCallback() { public void resultReceived(IPendingServiceCall call) { int streamId = (Integer) call.getResult(); // live buffer 0.5s / vod buffer 4s if (live) { conn.ping(new Ping(Ping.CLIENT_BUFFER, streamId, 500)); play(streamId, filename, -1, -1); } else { conn.ping(new Ping(Ping.CLIENT_BUFFER, streamId, 4000)); play(streamId, filename, 0, -1); } } }; @SuppressWarnings("unchecked") protected void onInvoke(RTMPConnection conn, Channel channel, Header header, Notify notify, RTMP rtmp) { super.onInvoke(conn, channel, header, notify, rtmp); System.out.println("onInvoke, header = " + header.toString()); System.out.println("onInvoke, notify = " + notify.toString()); System.out.println("onInvoke, rtmp = " + rtmp.toString()); Object obj = notify.getCall().getArguments().length > 0 ? notify .getCall().getArguments()[0] : null; if (obj instanceof Map) { Map<String, String> map = (Map<String, String>) obj; String code = map.get("code"); if (StatusCodes.NS_PLAY_STOP.equals(code)) { synchronized (ClientTest.class) { finished = true; ClientTest.class.notifyAll(); } disconnect(); System.out.println("Disconnected"); } } } /** * @return the live */ public boolean isLive() { return live; } /** * @param live * the live to set */ public void setLive(boolean live) { this.live = live; }; }
3 dsj 中显示捕获的视频流||||||dsj调用本地摄像头向red5 发送视频流
package com.oatos.red5; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import javax.swing.JFrame; import de.humatic.dsj.DSCapture; import de.humatic.dsj.DSFilterInfo; import de.humatic.dsj.DSFiltergraph; import de.humatic.dsj.DSGraph; import de.humatic.dsj.DSJUtils; import de.humatic.dsj.DSMovie; import de.humatic.dsj.JSampleBuffer; import de.humatic.dsj.SampleBuffer; import de.humatic.dsj.SwingMovieController; import de.humatic.dsj.sink.RTMPSink; import de.humatic.dsj.src.RTMPSource; import de.humatic.dsj.src.Source; import de.humatic.dsj.src.rtmp.ConnectionParameter; import de.humatic.dsj.src.rtmp.RTMPMessage; import de.humatic.dsj.src.rtp.RTPChannel; public class DSJRTMP implements java.beans.PropertyChangeListener { private DSCapture graph; private String ip="localhost"; private int port=1935; private String app="oflaDemo"; private String url = "rtmp://localhost/oflaDemo"; private String streamName = "stream1371608283848"; public static void main(String[] args) throws Exception { //new DSJRTMP().TestRTMP(); new DSJRTMP().testRTMPSoucre(); } public JFrame addFrame(){ JFrame f = new JFrame("dsj RTMP"); f.pack(); f.setVisible(true); f.setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); return f; } /*** * 本地摄像头往 red5 发送视频流 * @throws Exception */ public void TestRTMP() throws Exception { Source source = new Source(); // source.createGraph(arg0); //javax.swing.JFrame f = new javax.swing.JFrame("dsj SimpleCapture"); DSFilterInfo[][] dsi = DSCapture.queryDevices(); System.out.println(dsi); /** this sample only uses video **/ graph = new DSCapture(DSFiltergraph.DD7, dsi[0][0], false, DSFilterInfo .doNotRender(), this); // graph.createBufferStrategy(1024); System.out.println(graph); addFrame().add(java.awt.BorderLayout.CENTER, graph.asComponent()); // f.add(java.awt.BorderLayout.SOUTH, new SwingMovieController(graph)); RTMPSink rtmpsink = new RTMPSink(graph,url,streamName,dsi[0][0],dsi[1][0],-1); System.out.println(rtmpsink); // rtmpsink.sendRTMP(arg0); // DsSampleBuffer sb = new JSampleBuffer(); // rtmpsink.sampleReceived(); // RTPChannel channel = new RTPChannel(); // RTMPMessage msg = new RTMPMessage(); // // f.pack(); // f.setVisible(true); // f.setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); } /** * 连接red5 接收视频流 * @throws Exception */ void testRTMPSoucre() throws Exception{ //ConnectionParameter params = new ConnectionParameter("", nested, AMF.OBJECT, ConnectionParameter.APPEND); java.beans.PropertyChangeListener pc = new java.beans.PropertyChangeListener(){ @Override public void propertyChange(PropertyChangeEvent evt) { System.out.println("----"+evt); }}; // RTMPSource rs = new RTMPSource(ip,port,app,streamName,pc); //RTMPSource rs = new RTMPSource(url,"hobbit_vp6.flv", -1, this); RTMPSource rs = new RTMPSource(url,streamName, -1, this); System.out.println(rs.getPath()); System.out.println(rs.getMaxTimeLoaded()); System.out.println(rs.getMediaTypes()); //DSGraph ds = rs.createGraph(DSFiltergraph. VIDEO_BUFFER_REQUEST); //System.out.println(rs.getBuffered()); //System.out.println(ds); DSMovie dm = new DSMovie("rtmp://localhost/oflaDemo",DSFiltergraph.DD7,this); //DSMovie dm = new DSMovie("F:/install_soft/red5/webapps/oflaDemo/streams/hobbit_vp6.flv",DSFiltergraph.DD7,this); //addFrame().add(java.awt.BorderLayout.CENTER,dm.asComponent()); // JFrame f = new JFrame("dsj RTMP"); addFrame().add(java.awt.BorderLayout.CENTER, dm.asComponent()); //f.pack(); // f.setVisible(true); //f.setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); } @Override public void propertyChange(PropertyChangeEvent evt) { switch (DSJUtils.getEventType(evt)) { } } }
这个类是有问题的,接受的到的流无法显示,可能需要转化成某种格式。
由于是匆匆整理,省略了red5 的安装,red5跟tomcat 一样使用起来简单,openmeetings 中的屏幕共享代码我是copy他的做一些修改,但是怎么去用java将他显示?不知道。要是用flex 简直soeasy.明天整理完再写上完整版的,希望本坛神人能help me ! 不然心里有个坎,过不去!!
相关推荐
1、文件内容:sblim-gather-provider-2.2.8-9.el7.rpm以及相关依赖 2、文件形式:tar.gz压缩包 3、安装指令: #Step1、解压 tar -zxvf /mnt/data/output/sblim-gather-provider-2.2.8-9.el7.tar.gz #Step2、进入解压后的目录,执行安装 sudo rpm -ivh *.rpm 4、更多资源/技术支持:公众号禅静编程坊
本图书进销存管理系统管理员功能有个人中心,用户管理,图书类型管理,进货订单管理,商品退货管理,批销订单管理,图书信息管理,客户信息管理,供应商管理,库存分析管理,收入金额管理,应收金额管理,我的收藏管理。 用户功能有个人中心,图书类型管理,进货订单管理,商品退货管理,批销订单管理,图书信息管理,客户信息管理,供应商管理,库存分析管理,收入金额管理,应收金额管理。因而具有一定的实用性。 本站是一个B/S模式系统,采用Spring Boot框架,MYSQL数据库设计开发,充分保证系统的稳定性。系统具有界面清晰、操作简单,功能齐全的特点,使得图书进销存管理系统管理工作系统化、规范化。本系统的使用使管理人员从繁重的工作中解脱出来,实现无纸化办公,能够有效的提高图书进销存管理系统管理效率。 关键词:图书进销存管理系统;Spring Boot框架;MYSQL数据库
2024中国在人工智能领域的创新能力如何研究报告.pdf
人脸识别项目实战
人脸识别项目实战
人脸识别项目实战
内容概要:本文档详细介绍了基于CEEMDAN(完全自适应噪声集合经验模态分解)的方法实现时间序列信号分解的具体项目。文中涵盖项目背景介绍、主要目标、面临的挑战及解决方案、技术创新点、应用领域等多方面内容。项目通过多阶段流程(数据准备、模型设计与构建、性能评估、UI设计),并融入多项关键技术手段(自适应噪声引入、并行计算、机器学习优化等)以提高非线性非平稳信号的分析质量。同时,该文档包含详细的模型架构描述和丰富的代码样例(Python代码),有助于开发者直接参考与复用。 适合人群:具有时间序列分析基础的科研工作者、高校教师与研究生,从事信号处理工作的工程技术人员,或致力于数据科学研究的从业人员。 使用场景及目标:此项目可供那些面临时间序列数据中噪声问题的人群使用,尤其适用于需从含有随机噪音的真实世界信号里提取有意义成分的研究者。具体场景包括但不限于金融市场趋势预测、设备故障预警、医疗健康监控以及环境质量变动跟踪等,旨在提供一种高效的信号分离和分析工具,辅助专业人士进行精准判断和支持决策。 其他说明:本文档不仅限于理论讲解和技术演示,更着眼于实际工程项目落地应用,强调软硬件资源配置、系统稳定性测试等方面的细节考量。通过完善的代码实现说明以及GUI界面设计指南,使读者能够全面理解整个项目的开发流程,同时也鼓励后续研究者基于已有成果继续创新拓展,探索更多的改进空间与发展机遇。此外,针对未来可能遇到的各种情况,提出了诸如模型自我调整、多模态数据融合等发展方向,为长期发展提供了思路指导。
监护人,小孩和玩具数据集 4647张原始图片 监护人 食物 孩子 玩具 精确率可达85.4% pasical voc xml格式
人脸识别项目实战
人脸识别项目实战
在智慧园区建设的浪潮中,一个集高效、安全、便捷于一体的综合解决方案正逐步成为现代园区管理的标配。这一方案旨在解决传统园区面临的智能化水平低、信息孤岛、管理手段落后等痛点,通过信息化平台与智能硬件的深度融合,为园区带来前所未有的变革。 首先,智慧园区综合解决方案以提升园区整体智能化水平为核心,打破了信息孤岛现象。通过构建统一的智能运营中心(IOC),采用1+N模式,即一个智能运营中心集成多个应用系统,实现了园区内各系统的互联互通与数据共享。IOC运营中心如同园区的“智慧大脑”,利用大数据可视化技术,将园区安防、机电设备运行、车辆通行、人员流动、能源能耗等关键信息实时呈现在拼接巨屏上,管理者可直观掌握园区运行状态,实现科学决策。这种“万物互联”的能力不仅消除了系统间的壁垒,还大幅提升了管理效率,让园区管理更加精细化、智能化。 更令人兴奋的是,该方案融入了诸多前沿科技,让智慧园区充满了未来感。例如,利用AI视频分析技术,智慧园区实现了对人脸、车辆、行为的智能识别与追踪,不仅极大提升了安防水平,还能为园区提供精准的人流分析、车辆管理等增值服务。同时,无人机巡查、巡逻机器人等智能设备的加入,让园区安全无死角,管理更轻松。特别是巡逻机器人,不仅能进行360度地面全天候巡检,还能自主绕障、充电,甚至具备火灾预警、空气质量检测等环境感知能力,成为了园区管理的得力助手。此外,通过构建高精度数字孪生系统,将园区现实场景与数字世界完美融合,管理者可借助VR/AR技术进行远程巡检、设备维护等操作,仿佛置身于一个虚拟与现实交织的智慧世界。 最值得关注的是,智慧园区综合解决方案还带来了显著的经济与社会效益。通过优化园区管理流程,实现降本增效。例如,智能库存管理、及时响应采购需求等举措,大幅减少了库存积压与浪费;而设备自动化与远程监控则降低了维修与人力成本。同时,借助大数据分析技术,园区可精准把握产业趋势,优化招商策略,提高入驻企业满意度与营收水平。此外,智慧园区的低碳节能设计,通过能源分析与精细化管理,实现了能耗的显著降低,为园区可持续发展奠定了坚实基础。总之,这一综合解决方案不仅让园区管理变得更加智慧、高效,更为入驻企业与员工带来了更加舒适、便捷的工作与生活环境,是未来园区建设的必然趋势。
本届年会的主题是“青春梦想创新创业”。通过学术论文报告、创新创业项目展示、创业项目推介、工作研讨、联谊活动、大会报告等活动,全面展示大学生最新的创新创业成果。年会共收到491所高校推荐的学术论文756篇、创新创业展示项目721项、创业推介项目156项,合计1633项,为历届年会数量最高。经过36所“985”高校相关学科专家的初评以及国家级大学生创新创业训练计划专家组的复选,最终遴选出可参加本次年会的学术论文180篇,创新创业展示项目150个,创业推介项目45项,共计375项,涉及30个省市的236所高校。年会还收到了来自澳门特别行政区、俄罗斯的13项学术论文及参展项目。这些材料集中反映了各高校最新的创新创业教育成果,也直接体现了当代大学生的创新思维和实践能力。
人脸识别项目实战
6ES7215-1AG40-0XB0_V04.04.01固件4.5
在无人机上部署SchurVins的yaml配置文件
uniapp实战商城类app和小程序源码,包含后端API源码和交互完整源码。
基于MobileNet轻量级网络实现的常见30多种食物分类,包含数据集、训练脚本、验证脚本、推理脚本等等。 数据集总共20k左右,推理的形式是本地的网页推理
2024年央国企RPA市场研究报.pdf
VSCodeSetup-x64-1.98.0.rar vscode是一种简化且高效的代码编辑器,同时支持诸如调试,任务执行和版本管理之类的开发操作。它的目标是提供一种快速的编码编译调试工具。然后将其余部分留给IDE。vscode集成了所有一款现代编辑器所应该具备的特性,包括语法高亮、可定制的热键绑定、括号匹配、以及代码片段收集等。 Visual Studio Code(简称VSCode)是Microsoft开发的代码编辑器,它支持Windows,Linux和macOS等操作系统以及开源代码。它支持测试,并具有内置的Git版本控制功能以及开发环境功能,例如代码完成(类似于IntelliSense),代码段和代码重构等。编辑器支持用户定制的配置,例如仍在编辑器中时,可以更改各种属性和参数,例如主题颜色,键盘快捷键等,内置的扩展程序管理功能。