【PHP】控制摄像头缩放监控画面大小,并保存可视画面为图片

news2024/11/16 13:31:02

一、前言

功能描述

调用摄像头并可以控制缩放摄像头监控画面的大小,把可视画面保存为图片。

我使用的是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 data
			Webcam.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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1868301.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

初识前端工程化

前端工程化 一、接口文档管理 YAPI二、前端工程化1、前端工程化介绍2、环境准备 三、Vue 项目创建&简介1、Vue 项目创建2、Vue 项目简介3、运行 Vue 项目 四、Vue 组件库 Element UI1、Elment UI 简介2、Element UI 入门 五、Vue 项目中使用 axios六、Vue 路由1、Vue 路由简…

一种基于优化信息频带的旋转机械故障诊断方法(MATLAB)

特征提取是滚动轴承故障诊断及状态监测的关键&#xff0c;直接关系到轴承状态预示及故障识别的准确性&#xff0c;也是轴承故障诊断中的研究热点。考虑到轴承故障冲击会导致振动信号的形态改变&#xff0c;进而引起相关统计参数的变化&#xff0c;所以通过振动信号计算的统计量…

上海高考志愿填报小程序开发的主要功能

6月毕业季&#xff0c;高考学子刚经历了激烈的高考角逐&#xff0c;又迎来了志愿填报的大关。面对影响一生的高考志愿&#xff0c;如何填报显得尤为重要&#xff0c;面对广大学子的填报需求&#xff0c;上海高考志愿填报小程序为高考学子带来了福音。 一&#xff0e; 上海高考…

低空经济:新蓝海的启航与eVTOL动力系统测试的前瞻探索

引言&#xff1a;低空经济的新时代篇章 ​在2023年的全国两会上&#xff0c;“低空经济”首次跃然于政府工作报告之中&#xff0c;标志着这一新兴产业正式步入国家发展战略的核心舞台。工业和信息化部、科学技术部、财政部与中国民用航空局联合发布的《通用航空装备创新应用实…

小区物业管理收费系统源码小程序

便捷、透明、智能化的新体验 一款基于FastAdminUniApp开发的一款物业收费管理小程序。包含房产管理、收费标准、家属管理、抄表管理、在线缴费、业主公告、统计报表、业主投票、可视化大屏等功能。为物业量身打造的小区收费管理系统&#xff0c;贴合物业工作场景&#xff0c;轻…

【微前端-Single-SPA、qiankun的基本原理和使用】

背景 在实际项目中&#xff0c;随着日常跌倒导致的必然墒增&#xff0c;项目会越来越冗余不好维护&#xff0c;而且有时候一个项目会使用的其他团队的功能&#xff0c;这种跨团队不好维护和管理等等问题&#xff0c;所以基于解决这些问题&#xff0c;出现了微前端的解决方案。…

FFmpeg教程-二-代码实现录音

目录 一&#xff0c;实现步骤 二&#xff0c;具体实现 1&#xff0c;注册设备 2&#xff0c;获取输入格式对象 3&#xff0c;打开设备 4&#xff0c;采集数据 一&#xff0c;实现步骤 二&#xff0c;具体实现 1&#xff0c;注册设备 // 初始化libavdevice并注册所有输入…

Java版本Spring Cloud+SpringBoot b2b2c:Java商城实现一件代发设置及多商家直播带货商城搭建

一、产品简介 我们的JAVA版多商家入驻直播带货商城系统是一款全*面的电子商务平台&#xff0c;它允许商家和消费者在一个集成的环境中进行互动。系统采用先进的JAVA语言开发&#xff0c;提供多商家入驻、直播带货、B2B2C等多种功能&#xff0c;帮助用户实现线上线下的无缝对接…

M Farm RPG Assets Pack(农场RPG资源包)

🌟塞尔达的开场动画:风鱼之歌风格!🌟 像素参考:20*20 字体和声音不包括在内 资产包括: 1名身体部位分离的玩家和4个方向动画: 闲逛|散步|跑步|持有物品|使用工具|拉起|浇水 6个带有4个方向动画的工具 斧头|镐|喙|锄头|水壶|篮子 4个NPC,有4个方向动画: 闲逛|散步 �…

理解IP地址与域名:访问网站的基石

在互联网的世界里&#xff0c;每一次点击、每一次浏览都伴随着一个神秘的数字串——IP地址&#xff0c;以及一个易于记忆的字符串——域名。对于普通用户而言&#xff0c;这两者可能只是浏览网页时的“幕后英雄”&#xff0c;但实际上&#xff0c;它们构成了我们访问网站的基石…

人工神经网络是什么,其应用有哪些?

人工神经网络是什么&#xff0c;其应用有哪些&#xff1f; 当你阅读这篇文章时&#xff0c;你身体的哪个器官正在考虑它&#xff1f;当然是大脑&#xff01;但是你知道大脑是如何工作的吗&#xff1f;嗯&#xff0c;它有神经元或神经细胞&#xff0c;它们是大脑和神经系统的主要…

STM32HAL库 -- RS485 开发板通信(速记版)

在本章中&#xff0c; 我们将使用 STM32F429的串口 2 来实现两块开发板之间的 485 通信(半双工)。 RS485 简介 485&#xff08;一般称作 RS485/EIA-485&#xff09;隶属于 OSI 模型物理层&#xff0c;是串行通讯的一种。电气特性规定为 2 线&#xff0c;半双工&#xff0c;多…

java-数据结构与算法-02-数据结构-02-链表

文章目录 1. 概述2. 单向链表3. 单向链表&#xff08;带哨兵&#xff09;4. 双向链表&#xff08;带哨兵&#xff09;5. 环形链表&#xff08;带哨兵&#xff09;6. 习题E01. 反转单向链表-Leetcode 206E02. 根据值删除节点-Leetcode 203E03. 两数相加-Leetcode 2E04. 删除倒数…

匠心铸就服务品质,全视通技术服务获盘锦市中医医院高度认可

一声表扬&#xff0c;万分肯定 寥寥数语&#xff0c;情意深重 承载着荣誉 道出了心声 传达了谢意 倾注了期盼 字里行间的内容 是对全视通技术服务的高度认可 记录了全视通与盘锦市中医医院之间的双向奔赴 盘锦市中医医院表扬信是对全视通技术服务团队工作的高度认可&am…

JAVA进阶学习09

文章目录 一、双列集合Map1.1 双列集合介绍1.2 双列集合Map常见API1.3 Map集合遍历方式1.3.1 通过集合的全部键来遍历集合1.3.2 Map集合遍历方式21.3.3 Map集合遍历方式3 二、Map集合的实现类2.1 HashMap类2.2 LinkedHashMap2.3 TreeMap 三、可变参数四、Collections类五、集合…

【数据分享】《中国文化及相关产业统计年鉴》2013-2022

而今天要免费分享的数据就是2013-2022年间出版的《中国文化及相关产业统计年鉴》并以多格式提供免费下载。&#xff08;无需分享朋友圈即可获取&#xff09; 数据介绍 在过去的十年里&#xff0c;中国的文化及文化产业经历了翻天覆地的变化。随着《中国文化及相关产业统计年鉴…

ETO外汇:日元技术分析,美元/日元、欧元/日元、英镑/日元未来走势如何?

摘要&#xff1a; 根据近期的市场分析&#xff0c;美元/日元、欧元/日元和英镑/日元这三组货币对在未来的走势将受到多方面因素的影响。本文将从技术角度对每一组货币对进行详细分析&#xff0c;帮助投资者了解可能的支撑和阻力位&#xff0c;以及未来的走势预期。通过对关键技…

Python高精度浮点运算库之mpmath使用详解

概要 在科学计算和工程应用中,精确的数学计算至关重要。Python 作为一种灵活而强大的编程语言,提供了多种数学库,其中 mpmath 库因其高精度浮点运算和丰富的数学函数支持而备受关注。mpmath 库不仅适用于基本的高精度计算,还支持复数运算、矩阵运算和特殊函数计算,广泛应…

iptables(12)实际应用举例:策略路由、iptables转发、TPROXY

简介 前面的文章中我们已经介绍过iptables的基本原理,表、链的基本操作,匹配条件、扩展模块、自定义链以及网络防火墙、NAT等基本配置及原理。 这篇文章将以实际应用出发,列举一个iptables的综合配置使用案例,将我们前面所涉及到的功能集合起来,形成一个完整的配置范例。…

前端vue自定义鼠标指针的图标并且单击鼠标时点击的地方会出现烟花特效

//实现在某一个div内鼠标的指针形状呈自定义的图标 。&#xff08;也可以全局定义&#xff0c;当前时在某一个div内的实例&#xff09; //DOM <div class"firework-container" click"createFirework"></div> //js部分 const createFirework …