一、前言
功能描述
调用摄像头并可以控制缩放摄像头监控画面的大小,把可视画面保存为图片。
我使用的是USB摄像头,其他摄像头此方法应该也通用。
使用技术
使用到的技术比较简单,前端使用WebcamJS插件调用摄像头,并摄像头监控画面,使用CSS的transform属性来放大或缩小画面的大小。后端使用PHP的Imagick类库来缩放图片,最终保存图片到本地。
二、最终效果
Capture:保存可视区域图片;放大:放大可视区域画面;缩小:缩小可视区域画面;还原:还原可视区域画面。
三、业务逻辑说明
前端
① 调用摄像头:使用WebcamJS库调用摄像头,显示监控画面(注意:需要在https下才能使用此插件);
② 缩放画面:先初始可视区域的宽高,设置scale缩放比例,再使用CSS的transform属性来缩放画面大小(注意:transform属性只是在视觉上对图片进行了缩放,其实和图像的真实大小并不一致,因为我这里为了保持放大后的图像尺寸大小和原始图像尺寸大小在视觉上一致,所以我把多余的画面区域使用overflow隐藏了);
③ 数据传输后端:把图片数据和缩放比例传输给PHP后端进行处理。此时传输的图像数据是base64编码,尺寸大小并不是视觉上所看到的画面大小,这个需要在后端进行处理。
后端
① 接收前端传过来的数据(base64图片编码、缩放比例);
② 把接收的base64编码保存为图片到本地;
③ 对图片进行处理:使用Imagick类库对图像进行处理,前面说了前端传过来的图像尺寸并不是可视区域的尺寸,所以为了保存一致,需要对接收的原始图像进行缩放处理。需要两个步骤,先是根据放大比例计算并保存放大后的图片(是原始大小的图片,不是视觉大小的图片),再对该图片进行裁剪,裁剪方法是计算裁剪区域的起始坐标,这个坐标是从放大后图像的中心位置开始计算的,最后根据这个坐标和裁剪尺寸进行裁剪并保存新的图片。这样就得到了一个从放大后的图像中心为圆心,向外扩散裁剪;
④ 保存裁剪后的图片,进行后续操作。
四、代码
前端
<!doctype html><html lang="en">
<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>WebcamJS Test Page - Large Capture</title><style type="text/css">body { font-family: Helvetica, sans-serif; }h2, h3 { margin-top:0; }form { margin-top: 15px; }form > input { margin-right: 15px; }#my_camera { transition: transform 0.3s ease-in-out; /* 添加过渡效果,使变换更平滑 */ transform-origin: center center; /* 变换原点设置为图片中心 */ width: 100%; /* 初始尺寸设置为容器宽度 */ height: auto; /* 保持图片的宽高比 */ }#imageContainer{width: 640px; /* 设置你想要的容器宽度 */ height: 480px; /* 设置你想要的容器高度 */ overflow: hidden; /* 隐藏超出容器的部分 */ position: relative; /* 如果需要相对于容器定位图片,可以添加这个属性 */}</style>
</head>
<body><h1>WebcamJS Test Page - Large/Small Capture</h1><div id="imageContainer" style=""><div id="my_camera"></div></div><!-- A button for taking snaps --><form><input type=button value="Capture" onClick="take_snapshot()"><input type=button value="放大" id="zoomIn" ><input type=button value="缩小" id="zoomOut"><input type=button value="还原" id="reset"></form><script type="text/javascript" src="/static/index/js/webcam.min.js"></script><script src="https://ajax.aspnetcdn.com/ajax/jquery/jquery-3.5.1.min.js"></script><script language="JavaScript">Webcam.set({width: 640,height: 480,image_format: 'jpeg',jpeg_quality: 90});Webcam.attach( '#my_camera' );</script><script language="JavaScript">function take_snapshot() {// take snapshot and get image dataWebcam.snap( function(data_uri) {console.log(scale)var imgBase64 = data_uri$.ajax({url:'/index/camera/photo',dataType:'JSON',type:'POST',data:{data:imgBase64,scale:scale},success:function (res) {console.log(res)}})});}var scale = 1; // 初始缩放比例 $('#zoomIn').click(function() { if (scale < 3) { // 限制最大缩放比例,这里设置为3 scale += 0.1; // 每次点击放大0.1 $('#my_camera').css('transform', 'scale(' + scale + ')'); } // 计算放大后的尺寸var originalWidth = $("#my_camera").width();var originalHeight = $("#my_camera").height();var zoomedWidth = originalWidth * scale; var zoomedHeight = originalHeight * scale; console.log(zoomedWidth)console.log(zoomedHeight)}); $('#zoomOut').click(function() { if (scale > 1) { // 限制最小缩放比例,这里设置为1 scale -= 0.1; // 每次点击缩小0.1 $('#my_camera').css('transform', 'scale(' + scale + ')'); } }); $('#reset').click(function() { scale = 1$('#my_camera').css('transform', 'scale(' + scale + ')'); }); </script></body>
</html>
后端
// 处理图像
public function photo()
{$image= input('post.data'); //接收base64数据$scale= input('post.scale'); //接收缩放比例//图片存放的路径$path = "uploads".DS."chufang".DS.date('Y-m-d', time()) . DS;// 检查该目录是否存在,不存在就创建if (!file_exists($path)) {mkdir($path, 0700, true); //创建目录chmod($path, 0700); //赋予权限}$uid = session('uid');//确保图片名唯一,防止重名产生覆盖$imageName = 'wx_' .$uid.'_'. time() . rand(1000, 9000) . '.jpg';//判断是否有逗号 如果有就截取后半部分if (strstr($image,",")){$image = explode(',',$image);$image = $image[1];}//图片完整路径$imageSrc= ROOT_PATH .'public' .DS. $path . $imageName;// 生成文件夹和图片$r = file_put_contents($imageSrc, base64_decode($image));// 原始图像路径$sourceImagePath= $imageSrc;// 目标图像路径$targetImagePath = ROOT_PATH .'public' .DS. $path .'target.jpg'; // 实例化(原始图像路径)$image = new \Imagick($sourceImagePath);// 获取原始图像的尺寸 $originalWidth = $image->getImageWidth(); $originalHeight = $image->getImageHeight(); // 计算放大后图像的尺寸(这仅用于计算裁剪区域,最终图像尺寸保持不变) $scaledWidth = $originalWidth * $scale;$scaledHeight = $originalHeight * $scale;// 保存放大后的图像 $image->resizeImage($scaledWidth, $scaledHeight, \Imagick::FILTER_LANCZOS, 1); // 设定裁剪区域的尺寸(这里设置与原始图像一样大的尺寸) $cropWidth = $originalWidth * 1; // 如果比原始宽度大50%,可*1.5 $cropHeight = $originalHeight * 1; // 如果比原始高度大50%,可*1.5 // 计算裁剪区域的起始坐标(从放大后图像的中心开始) $startX = ($scaledWidth - $originalWidth) / 2; $startY = ($scaledHeight - $cropHeight) / 2; // 确保起始坐标是整数(因为像素坐标必须是整数) $startX = (int)round($startX); $startY = (int)round($startY); // 使用 Imagick 的 cropImage 方法裁剪图像 $image->cropImage($cropWidth, $cropHeight, $startX, $startY); // 保存新图像$image->writeImage($targetImagePath); // 清除资源 $image->clear(); $image->destroy(); }
五、资源下载
WebcamJS: jQuery移动端调用摄像头拍照插件WebcamJS
Imagick:PHP安装Imagick扩展库(网上有教程,可自行搜索)
完整代码下载:https://download.csdn.net/download/qq_25285531/89487658