"ERROR: SampleCB() - buffer sizes do not match " 解决方法

本文介绍了一种利用自定义视频输入类库实现多摄像头功能的方法,解决了OpenCV中仅支持单摄像头的问题,通过代码示例展示了如何在Windows环境下进行多摄像头视频流的实时处理。

本人原创,转载请标明转载地址。http://blog.youkuaiyun.com/jia_zhengshen/article/details/9980495

opencv的highgui模块在windows的实现中使用开源的图像显示函数库:videoInput,但是为了同Linux等兼容,highgui模块做的对PAL,NTSC模块做的不是很好,并且应该是不支持多摄像头的。通过查看源码得知,虽然ideoInput是支持多摄像头的,但是由于VideoCapture 类中的VideoInput的性质被设置为“private static ”只能有一个VideoInput实例在opencv中运行,所以opencv中不支持多摄像头,而且由于VI被设置为private所以这个VI的性质是不能更改的。


所以我放弃了直接使用opencv的VideoCapture模块。改为直接采用其底层的VideoInput来实现多摄像头,解决"ERROR: SampleCB() - buffer sizes do not match "问题。

做法如下:

1.下载videoinput类库,遇到问题,现在由于其不再更新,所以最高版本的类库为vs08版本,我用的是vs10 ,经过试验10的可以使用这个由vs08编译的类库。

2.设置各种路径,lib ,include路径。估计你能看到这篇文章,这点设置应该小意思。

3.包含videoinput.h头文件。

4.写代码,把videoinput类中的data直接赋值给cv::mat,或者IplImage。

qq是如何实现的呢?看看他是如何抄袭的啊,

     



你按下“画质调节”会出现神马情况呢???????????????在运行一下下面的代码,是不是界面惊人的类似呢?原来qq也是用的videoInput这个库。


下面是个我写的简单的小例子,还希望大家能够指点。

#pragma comment(linker,"/NODEFAULTLIB:atlthunk.lib")            
//据说上面的一句话必不可少。
#include <iostream>
#include "opencv2/opencv.hpp"
#include "opencv2/gpu/gpu.hpp"
#include<opencv2\highgui\highgui.hpp>
using namespace std;
using namespace cv;
#include"videoInput.h"
int main (int argc, char* argv[])
{
	videoInput::listDevices();//列出系统能够找到的所有的摄像头
	videoInput *VI = new videoInput();
	int device =1;//设备号
	//VI->setPhyCon(0,VI_COMPOSITE);
	VI->setupDevice(device );//打开设备
	VI->setFormat(device,VI_PAL_B);//我用的摄像头是PAL_B格式的,所以设置成这个格式的,其实可以不要。
	VI->showSettingsWindow(device);//使用widows的对话框来设置摄像头的格式等。可以替代掉上面的那句话。、、打开qq的画质调节,发现你的对话框和qq的竟然一样?????
														//原来qq也是用ideoInput来实现的。
	int height = VI->getHeight(device);
	int width = VI->getWidth(device );
	cout<<"height "<<height<<" width "<<width<<endl;
	IplImage *img = cvCreateImage(cvSize(width,height),8,3);
	std::cout<<VI->isDeviceSetup(device)<<std::endl;//查看设备是否启动
	std::cout<<VI->isFrameNew(device)<<std::endl;
	std::cout<<VI->getDeviceName(device)<<std::endl;//得到设备名称。
	std::cout<<VI->devicesFound<<std::endl;//一共有多少个设备。
	int i=0;
	//OPENCV C++ INTERFACE 
	Mat cmat;
	cmat.create(height,width,CV_8UC3);
	Mat cmat2;
	cmat2.create(width,height,CV_8UC3);
	while(1)
	{
		//while(!VI->isFrameNew(0))
			//cout<<i++;

		if(VI->isFrameNew(device) )
		{
			VI->getPixels(device,(unsigned char*)img->imageData,false,true);//IplImage 格式
			VI->getPixels(device,(unsigned char*)cmat.data,false,false);//opencv 的c++接口的转化。
			VI->getPixels(device,(unsigned char*)cmat2.data,false,false);
			imshow("tt",cmat);
			imshow("tt2",cmat2);
			cvShowImage("hello",img);
			if( cvWaitKey(2) >=0)
				break;
		}
	}
	VI->stopDevice(1);//释放设备。
	getchar();
	
    return 0;
} 


<template> <view class="container"> <!-- 操作按钮区 --> <view class="card"> <button class="btn primary" @click="chooseFileNative"> 📱 使用原生选择器 </button> <button class="btn outline" @click="triggerFileInput"> 🖼️ 选择文件(浏览器方式) </button> <!-- 隐藏的 input --> <input type="file" ref="fileInputRef" :accept="acceptTypes" multiple @change="handleFiles" style="display: none" /> </view> <!-- 已选文件列表 --> <view class="card"> <text class="section-title">📤 已选文件</text> <view class="file-list" v-if="files.length > 0"> <view class="file-item" v-for="(file, index) in files" :key="index"> <text> <strong>📄 名称:</strong> {{ file.name }}<br /> <strong>📏 大小:</strong> {{ formatSize(file.size) }}<br /> <strong>🏷️ 类型:</strong> {{ file.type || '未知' }} </text> <!-- 图片预览 --> <image v-if="file.type?.startsWith('image/')" :src="file.url" mode="aspectFit" class="preview-img" /> <!-- 视频提示 --> <text v-else-if="file.type?.startsWith('video/')"> 🎥 视频文件,可上传查看 </text> <!-- PDF 预览链接 --> <a v-else-if="getFileExt(file.name) === 'pdf'" :href="file.url" target="_blank" class="link" > 🔗 查看 PDF </a> </view> </view> <view v-else class="empty-tip"> <text>暂无文件,请先选择</text> </view> </view> </view> </template> <script setup> import { ref, reactive, onMounted } from 'vue' // 环境变量 const env = import.meta.env.MODE const baseUrl = ref(import.meta.env.VITE_DOMAIN_URL) // 文件输入引用 const fileInputRef = ref(null) // 可接受的文件类型(可根据需要调整) const acceptTypes = 'image/*,video/*,.pdf,.doc,.docx,.xls,.xlsx,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document' // 存储已选文件 const files = ref([]) // 记录上传状态 const uploading = reactive({}) // 格式化文件大小 const formatSize = (bytes) => { if (!bytes) return '0 KB' const k = 1024 const sizes = ['B', 'KB', 'MB', 'GB'] const i = Math.floor(Math.log(bytes) / Math.log(k)) return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i] } // 方法1:调用原生 JS Bridge const chooseFileNative = () => { if (window.NativeBridge && window.NativeBridge.chooseFile) { window.NativeBridge.chooseFile() } else { alert('原生功能不可用,将使用浏览器方式') triggerFileInput() } } // 安全获取文件扩展名 const getFileExt = (filename) => { if (!filename) return '' const match = filename.trim().toLowerCase().match(/\.([a-z0-9]+)$/) return match ? match[1] : '' } // 方法2:触发文件选择(动态创建 input,确保 click 可用) const triggerFileInput = () => { const input = document.createElement('input') input.type = 'file' input.accept = 'image/*,video/*,.pdf,.doc,.docx,.xls,.xlsx,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document' input.multiple = true input.style.display = 'none' document.body.appendChild(input) input.onchange = (event) => { handleFiles(event) document.body.removeChild(input) } input.click() // 这里一定会成功调用原生 click } // 处理 input 选择的文件 const handleFiles = async (event) => { console.log("🚀 ~ handleFiles ~ event:", event) const selectedFiles = event.target.files if (!selectedFiles) return for (let file of Array.from(selectedFiles)) { const url = URL.createObjectURL(file) console.log("🚀 ~ handleFiles ~ url:", url) const base64 = await readFileAsBase64(file) // 🔥 添加 base64 console.log("🚀 ~ handleFiles ~ base64:", base64) files.value.push({ name: file.name, size: file.size, type: file.type, url, // 预览用 base64 // 新增:base64 流 }) } } // 工具函数:将 Blob/File 转为 base64 const readFileAsBase64 = (file) => { return new Promise((resolve, reject) => { const reader = new FileReader() reader.onload = () => { // result 就是 base64 数据 URL: data:image/png;base64,... resolve(reader.result) } reader.onerror = reject reader.readAsDataURL(file) // 开始读取为 base64 }) } // 接收原生返回的文件(JS Bridge 回调) function onNativeFileSelected(filePath, fileName, fileSize, mimeType) { console.log("🚀 ~ onNativeFileSelected1 ~ filePath:", filePath) console.log("🚀 ~ onNativeFileSelected2 ~ fileName:", fileName) console.log("🚀 ~ onNativeFileSelected3 ~ fileSize:", fileSize) console.log("🚀 ~ onNativeFileSelected4 ~ mimeType:", mimeType) try { // 添加防御判断 if (!fileName || typeof fileName !== 'string') { fileName = 'unknown_file' } if (!fileSize || typeof fileSize !== 'number') { fileSize = 0 } if (!mimeType) mimeType = 'application/octet-stream' const fakeFile = new File([], fileName, { type: mimeType }) const blobUrl = URL.createObjectURL(fakeFile) files.value.push({ name: fileName, size: fileSize, type: mimeType, nativePath: filePath, url: blobUrl }) } catch (error) { console.log("🚀 ~ onNativeFileSelected ~ error:", error) } } // 暴露给原生调用(必须挂载到 window) onMounted(() => { window.onNativeFileSelected = onNativeFileSelected console.log('[H5] 页面加载完成,等待文件选择...') }) </script> <style scoped lang="scss"> .container { padding: 20px; background: #f8f9fa; min-height: 100vh; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; } .card { background: white; border-radius: 12px; padding: 20px; box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); margin-bottom: 20px; } .btn { display: block; width: 100%; padding: 15px; margin: 10px 0; border: none; border-radius: 8px; font-size: 16px; text-align: center; cursor: pointer; &.primary { background: #1a73e8; color: white; } &.outline { background: #e8f0fe; color: #1a73e8; } } .section-title { font-size: 16px; font-weight: 600; margin-bottom: 15px; display: block; } .file-list { display: flex; flex-direction: column; gap: 15px; } .file-item { padding: 15px; background: #f1f3f5; border-radius: 8px; font-size: 14px; position: relative; } .preview-img { max-width: 100%; max-height: 200px; margin-top: 10px; border-radius: 6px; } .link { color: #1a73e8; text-decoration: underline; margin-top: 8px; display: inline-block; } .empty-tip { color: #666; font-style: italic; text-align: center; padding: 20px 0; } </style> 修改当前组件,让它和饿了么Ui的上传组件的功能相同,并且因为当前组件是小程序跳转进入的页面,希望在选择文件后,点击返回按钮可以把所有选中的文件信息携带回小程序
最新发布
09-29
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值