Android 图片相识度比较(pHash)

news2024/10/22 16:31:44

概述

在 Android 中,要比对两张 Bitmap 图片的相似度,常见的方法有基于像素差异直方图比较、或者使用一些更高级的算法如 SSIM(结构相似性)感知哈希(pHash)

1. 基于像素的差异比较

可以逐像素比较两张 Bitmap,计算它们之间的差异。以下是一个简单的逐像素比较的例子:

public static double compareBitmaps(Bitmap bitmap1, Bitmap bitmap2) {
    if (bitmap1.getWidth() != bitmap2.getWidth() || bitmap1.getHeight() != bitmap2.getHeight()) {
        throw new IllegalArgumentException("Bitmap sizes are different!");
    }

    int width = bitmap1.getWidth();
    int height = bitmap1.getHeight();
    long diff = 0;

    for (int y = 0; y < height; y++) {
        for (int x = 0; x < width; x++) {
            int pixel1 = bitmap1.getPixel(x, y);
            int pixel2 = bitmap2.getPixel(x, y);

            int r1 = Color.red(pixel1);
            int g1 = Color.green(pixel1);
            int b1 = Color.blue(pixel1);

            int r2 = Color.red(pixel2);
            int g2 = Color.green(pixel2);
            int b2 = Color.blue(pixel2);

            // 计算 RGB 差异
            diff += Math.abs(r1 - r2);
            diff += Math.abs(g1 - g2);
            diff += Math.abs(b1 - b2);
        }
    }

    // 最大可能差异
    double maxDiff = 3L * 255 * width * height;

    // 返回 0 到 1 的值,越小表示相似度越高
    return (double) diff / maxDiff;
}

这段代码计算两张图片的 RGB 差异,返回的结果范围在 0-1 之间,数值越接近 0 表示图片越相似。

2. 基于直方图的比较

通过比较两张图片的颜色直方图来评估相似度。直方图可以捕捉图像的颜色分布,而不关心具体像素位置。

public static double compareHistograms(Bitmap bitmap1, Bitmap bitmap2) {
    int[] histogram1 = new int[256];
    int[] histogram2 = new int[256];

    // 计算两张图的灰度直方图
    for (int y = 0; y < bitmap1.getHeight(); y++) {
        for (int x = 0; x < bitmap1.getWidth(); x++) {
            int pixel1 = bitmap1.getPixel(x, y);
            int gray1 = (Color.red(pixel1) + Color.green(pixel1) + Color.blue(pixel1)) / 3;
            histogram1[gray1]++;
            
            int pixel2 = bitmap2.getPixel(x, y);
            int gray2 = (Color.red(pixel2) + Color.green(pixel2) + Color.blue(pixel2)) / 3;
            histogram2[gray2]++;
        }
    }

    // 计算直方图的差异
    double diff = 0;
    for (int i = 0; i < 256; i++) {
        diff += Math.abs(histogram1[i] - histogram2[i]);
    }

    return diff / (bitmap1.getWidth() * bitmap1.getHeight());
}

3. 使用 SSIM(结构相似性)

SSIM 是一种用来衡量两张图片结构相似性的算法,它比简单的像素差异或直方图比较更准确。Android SDK 没有内置的 SSIM 方法,但可以引入第三方库或者自己实现。SSIM 主要关注三方面:亮度、对比度和结构。

4. 感知哈希(pHash)

pHash 是一种图像哈希技术,它可以生成图片的“指纹”,然后比较两个哈希值的相似性。与传统哈希方法不同,pHash 对于图像的细微改变(例如缩放、旋转)不敏感。

可以通过第三方库实现 pHash,比如 ImageHash 库,或者自己实现基于 DCT(离散余弦变换)的算法。

// 引入第三方库 ImageHash 进行哈希比较
String hash1 = ImageHash.hash(bitmap1);
String hash2 = ImageHash.hash(bitmap2);

int similarity = ImageHash.compare(hash1, hash2);

一般来说:

  • 对于简单的图像比较,基于像素差异的方式即可。
  • 如果要忽略图片的细微变动,直方图或感知哈希是更合适的选择。
  • SSIM 适用于对图像结构有更高要求的场景。

实现

图像比较的算法应用相当广泛, 本文基于感知哈希算法, 用于识别视频帧图像的左右两部分的相似度, 从而判断视频是否是一个左右眼的VR视频格式, 本文采用 感知哈希(pHash) 算法, 它非常适合处理具有细微变化的图像,如裁剪、缩放、亮度变化等。

感知哈希(pHash)是一种用于衡量图像相似度的算法,它通过将图像转换为频域信息,提取其视觉特征来生成一个哈希值。pHash 具有鲁棒性,能够忽略图像的小幅度变动、旋转和缩放等影响。下面是 pHash 算法的实现步骤及其原理。

pHash 算法的实现步骤

  1. 转换为灰度图:将图片转换为灰度图像,以便降低复杂度,并去除颜色信息的影响。

  2. 缩小尺寸:将图像缩小到一个固定的尺寸(例如 32x32),目的是去除高频细节,保留图片的整体特征。这一步骤在后续的离散余弦变换(DCT)中很重要。

  3. 离散余弦变换(DCT):对缩小后的图像执行离散余弦变换,将图像从空间域转换到频率域。这种转换能提取图像的低频信息,忽略高频噪声。

  4. 截取低频部分:只保留 DCT 结果的左上角部分(例如 8x8 的矩阵),因为这部分包含图像的主要信息。

  5. 计算均值:计算截取的低频部分的均值。

  6. 生成哈希值:将 DCT 中每个像素值与均值进行比较,生成一个二进制序列。如果某个像素值大于均值,置 1,否则置 0。最终的哈希值是由这个二进制序列构成。

参考pHash 算法实现

import android.graphics.Bitmap;
import android.graphics.Color;
import java.util.Arrays;

public class ImagePHash {

    // 默认使用 32x32 大小
    private static final int SIZE = 32;
    // DCT 截取的大小(例如 8x8)
    private static final int SMALLER_SIZE = 8;

    public String getHash(Bitmap img) {
        // 1. 转换为灰度图像
        Bitmap grayImg = toGrayscale(img);

        // 2. 缩小图片
        Bitmap smallImg = Bitmap.createScaledBitmap(grayImg, SIZE, SIZE, false);

        // 3. 转换为二维数组
        double[][] vals = new double[SIZE][SIZE];
        for (int x = 0; x < SIZE; x++) {
            for (int y = 0; y < SIZE; y++) {
                vals[x][y] = Color.red(smallImg.getPixel(x, y));
            }
        }

        // 4. 对图像执行离散余弦变换(DCT)
        double[][] dctVals = applyDCT(vals);

        // 5. 截取 DCT 左上角的 8x8 部分
        double[] dctLowFreq = new double[SMALLER_SIZE * SMALLER_SIZE];
        for (int x = 0; x < SMALLER_SIZE; x++) {
            for (int y = 0; y < SMALLER_SIZE; y++) {
                dctLowFreq[x * SMALLER_SIZE + y] = dctVals[x][y];
            }
        }

        // 6. 计算均值
        double avg = Arrays.stream(dctLowFreq).average().orElse(0.0);

        // 7. 生成哈希值
        StringBuilder hash = new StringBuilder();
        for (double value : dctLowFreq) {
            hash.append(value > avg ? "1" : "0");
        }

        return hash.toString();
    }

    // 转换为灰度图像
    private Bitmap toGrayscale(Bitmap img) {
        int width = img.getWidth();
        int height = img.getHeight();
        Bitmap grayscaleImg = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);

        for (int y = 0; y < height; y++) {
            for (int x = 0; x < width; x++) {
                int pixel = img.getPixel(x, y);
                int red = Color.red(pixel);
                int green = Color.green(pixel);
                int blue = Color.blue(pixel);
                int gray = (red + green + blue) / 3;
                int newPixel = Color.rgb(gray, gray, gray);
                grayscaleImg.setPixel(x, y, newPixel);
            }
        }
        return grayscaleImg;
    }

    // 执行离散余弦变换(DCT)
    private double[][] applyDCT(double[][] f) {
        int N = f.length;
        double[][] F = new double[N][N];
        for (int u = 0; u < N; u++) {
            for (int v = 0; v < N; v++) {
                double sum = 0.0;
                for (int i = 0; i < N; i++) {
                    for (int j = 0; j < N; j++) {
                        sum += f[i][j] *
                               Math.cos((2 * i + 1) * u * Math.PI / (2.0 * N)) *
                               Math.cos((2 * j + 1) * v * Math.PI / (2.0 * N));
                    }
                }
                double alphaU = (u == 0) ? Math.sqrt(1.0 / N) : Math.sqrt(2.0 / N);
                double alphaV = (v == 0) ? Math.sqrt(1.0 / N) : Math.sqrt(2.0 / N);
                F[u][v] = alphaU * alphaV * sum;
            }
        }
        return F;
    }

    // 比较两个哈希值,返回汉明距离(不同位数的个数)
    public int hammingDistance(String hash1, String hash2) {
        int distance = 0;
        for (int i = 0; i < hash1.length(); i++) {
            if (hash1.charAt(i) != hash2.charAt(i)) {
                distance++;
            }
        }
        return distance;
    }
}

对比效果如下(使用ListView 显示多张图片对比结果, 一帧视频图像从中间切割左右两部分, 分别显示在列表项的左右两侧, 中间的文字输出比较结果的汉明值, 值越小图像差异越小):
在这里插入图片描述
在这里插入图片描述

原始测试图片(从一个VR视频中截取出的视频帧):
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

代码分享:

test_img_diff.xml 布局

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/rlRoot">
    <ListView android:id="@+id/lv"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
</RelativeLayout>

ListView 的item 布局: item_img_diff.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <ImageView android:id="@+id/ivLeft"
        android:layout_width="128dp"
        android:layout_height="72dp"/>

    <ImageView android:id="@+id/ivRight"
        android:layout_width="128dp"
        android:layout_height="72dp"
        android:layout_alignParentRight="true"/>

    <TextView android:id="@+id/tvRes"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:textSize="18sp"
        android:textColor="#FFFFFFFF"/>
</RelativeLayout>

主界面Activity: ImgDiffTester.java

public class ImgDiffTester extends Activity implements View.OnClickListener {
	final String TAG = "ImgDiffTester";
	ListView lv;
	ImgListAdapter adapter;
	@Override
	protected void onCreate(@Nullable Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.test_img_diff);
		findViewById(R.id.rlRoot).setOnClickListener(this);
		lv = (ListView) findViewById(R.id.lv);
		adapter = new ImgListAdapter();
		lv.setAdapter(adapter);
		startCompare();
	}

	void startCompare(){
		new Thread(){
			@Override
			public void run() {
				File[] fs = new File("/sdcard/Download/").listFiles(new FileFilter() {
					@Override
					public boolean accept(File file) {
						return file.getName().endsWith(".png");
					}
				});
				for(File f : fs){
					Bitmap bm = BitmapFactory.decodeFile(f.getAbsolutePath());
					compareBitmapAndShow(bm);
				}

				lv.post(new Runnable() {
					@Override
					public void run() {
						adapter.notifyDataSetChanged();
					}
				});
			}
		}.start();
	}
	void compareBitmapAndShow(Bitmap bm){
		if(bm != null && bm.getWidth() > 0 && bm.getHeight() > 0) {

			final Bitmap bm1 = BitmapUtils.clipBitmapWidthBounds(bm, new Rect(0, 0, bm.getWidth() / 2, bm.getHeight()));
			//bm1 = BitmapFactory.decodeFile("/sdcard/l.png");
			final Bitmap bm2 = BitmapUtils.clipBitmapWidthBounds(bm, new Rect(bm.getWidth() / 2, 0, bm.getWidth(), bm.getHeight()));
			//bm2 = BitmapFactory.decodeFile("/sdcard/r.png");
			try {
				Bitmap[] scaled = new Bitmap[2];
				//scaled[0] = Bitmap.createBitmap(pHash.DCT_LENGTH, pHash.DCT_LENGTH, Bitmap.Config.ARGB_8888);
				//scaled[1] = Bitmap.createBitmap(pHash.DCT_LENGTH, pHash.DCT_LENGTH, Bitmap.Config.ARGB_8888);
				//int cmp = pHash.compareBitmap(bm1, bm2, scaled, false);
				long st = SystemClock.uptimeMillis();
				final int cmp = ImagePHash.compareBitmap(bm1, bm2);
				long et = SystemClock.uptimeMillis();
				Log.d(TAG, "compare " + cmp + " spend " + (et - st) + " ms");
				Item item = new Item();
				item.l = bm1;
				item.r = bm2;
				item.res = "Result: " + cmp + ", spend " + (et - st) + " ms";
				adapter.items.add(item);
			} catch (Exception e) {
				throw new RuntimeException(e);
			}
		}
	}
	public static class ImagePHash {

		// 默认使用 32x32 大小
		private static final int SIZE = 32;
		// DCT 截取的大小(例如 8x8)
		private static final int SMALLER_SIZE = 8;

		public static int compareBitmap(Bitmap bm1, Bitmap bm2){
			String h1 = getHash(bm1);
			String h2 = getHash(bm2);
			return hammingDistance(h1, h2);
		}
		@SuppressLint("NewApi")
		public static String getHash(Bitmap img) {
			long st = SystemClock.uptimeMillis();
			// 1. 转换为灰度图像
			Bitmap grayImg = toGrayscale(img);

			// 2. 缩小图片
			Bitmap smallImg = Bitmap.createScaledBitmap(grayImg, SIZE, SIZE, false);

			// 3. 转换为二维数组
			double[][] vals = new double[SIZE][SIZE];
			for (int x = 0; x < SIZE; x++) {
				for (int y = 0; y < SIZE; y++) {
					vals[x][y] = Color.red(smallImg.getPixel(x, y));
				}
			}

			long ct1 = SystemClock.uptimeMillis();
			// 4. 对图像执行离散余弦变换(DCT)
			double[][] dctVals = applyDCT(vals);
			long ct2 = SystemClock.uptimeMillis();

			// 5. 截取 DCT 左上角的 8x8 部分
			double[] dctLowFreq = new double[SMALLER_SIZE * SMALLER_SIZE];
			for (int x = 0; x < SMALLER_SIZE; x++) {
				for (int y = 0; y < SMALLER_SIZE; y++) {
					dctLowFreq[x * SMALLER_SIZE + y] = dctVals[x][y];
				}
			}

			// 6. 计算均值
			double avg = Arrays.stream(dctLowFreq).average().orElse(0.0);


			long ct3 = SystemClock.uptimeMillis();

			// 7. 生成哈希值
			StringBuilder hash = new StringBuilder();
			for (double value : dctLowFreq) {
				hash.append(value > avg ? "1" : "0");
			}
			Log.d("ImgDiff", (ct1 - st) + ", " + (ct2 - ct1));
			return hash.toString();
		}

		// 转换为灰度图像
		private static Bitmap toGrayscale(Bitmap img) {
			int width = img.getWidth();
			int height = img.getHeight();
			Bitmap grayscaleImg = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);

			for (int y = 0; y < height; y++) {
				for (int x = 0; x < width; x++) {
					int pixel = img.getPixel(x, y);
					int red = Color.red(pixel);
					int green = Color.green(pixel);
					int blue = Color.blue(pixel);
					int gray = (red + green + blue) / 3;
					int newPixel = Color.rgb(gray, gray, gray);
					grayscaleImg.setPixel(x, y, newPixel);
				}
			}
			return grayscaleImg;
		}

		// 执行离散余弦变换(DCT)
		private static double[][] applyDCT(double[][] f) {
			int N = f.length;
			double[][] F = new double[N][N];
			for (int u = 0; u < N; u++) {
				for (int v = 0; v < N; v++) {
					double sum = 0.0;
					for (int i = 0; i < N; i++) {
						for (int j = 0; j < N; j++) {
							sum += f[i][j] *
									Math.cos((2 * i + 1) * u * Math.PI / (2.0 * N)) *
									Math.cos((2 * j + 1) * v * Math.PI / (2.0 * N));
						}
					}
					double alphaU = (u == 0) ? Math.sqrt(1.0 / N) : Math.sqrt(2.0 / N);
					double alphaV = (v == 0) ? Math.sqrt(1.0 / N) : Math.sqrt(2.0 / N);
					F[u][v] = alphaU * alphaV * sum;
				}
			}
			return F;
		}

		// 比较两个哈希值,返回汉明距离(不同位数的个数)
		public static int hammingDistance(String hash1, String hash2) {
			int distance = 0;
			for (int i = 0; i < hash1.length(); i++) {
				if (hash1.charAt(i) != hash2.charAt(i)) {
					distance++;
				}
			}
			return distance;
		}
	}

	class ImgListAdapter extends BaseAdapter{
		ArrayList<Item> items = new ArrayList<>();
		@Override
		public int getCount() {
			return items.size();
		}

		@Override
		public Object getItem(int i) {
			return items.get(i);
		}

		@Override
		public long getItemId(int i) {
			return i;
		}

		@Override
		public View getView(int pos, View view, ViewGroup viewGroup) {
			if(view == null){
				view = getLayoutInflater().inflate(R.layout.item_img_diff, null, false);
			}
			((ImageView)view.findViewById(R.id.ivLeft)).setImageBitmap(items.get(pos).l);
			((ImageView)view.findViewById(R.id.ivRight)).setImageBitmap(items.get(pos).r);
			((TextView)view.findViewById(R.id.tvRes)).setText(items.get(pos).res);
			return view;
		}
	}
	class Item{
		Bitmap l, r;
		String res;
	}
}

温馨提示
本文算法及用例仅供参考, 未经大量测试验证
请谨慎阅读参考

参考

Android Bitmap亮度调节、灰度化、二值化、相似距离实现

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

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

相关文章

学习笔记——Test.pwn

前言&#xff1a;笔者也才接触Pwn&#xff0c;写这篇wp&#xff0c;记录目前所得感悟、思考、理解等。 存在错误&#xff0c;或者解释不通的地方&#xff0c;还请提出&#xff0c;已补足笔记的缺陷。 Pwn是什么&#xff1f; 我Pwn掉了你的电脑、我Pwn掉了你的设备…… 通俗的…

重庆大学软件工程考研,难度如何?

C哥专业提供——计软考研院校选择分析专业课备考指南规划 重大软件专业可谓是最好上岸的985院校&#xff01;重庆大学24考研各大学院复试录取情况已出&#xff0c; 我们先说学硕部分&#xff1a; 招生人数&#xff1a; 重庆大学软件工程学硕近几年计划统招人数都不多&#xf…

入选ECCV 2024!浙江大学联合微软亚洲研究院提出统一医学图像预训练框架UniMedI,打破医学数据异构化藩篱

让 AI 在某些条件下具备类似人类的反应能力&#xff0c;从而代替人类高效地从事特定工作&#xff0c;是 AI 领域研究人员孜孜不倦的追求。正如在医学图像和人工智能的交叉领域&#xff0c;基于视觉语言预训练的深度模型 (Visual-Language Pre-training, VLP) 凭借其自动化的特点…

Docker本地镜像发布到阿里云镜像服务的简易指南

1 阿里云容器镜像服务 阿里云容器镜像服务&#xff08;Alibaba Cloud Container Registry&#xff0c;简称ACR&#xff09;是一个为容器镜像、Helm Chart等云原生资产提供安全托管及高效分发的平台。它支持多架构容器镜像&#xff0c;包括Linux、Windows、ARM等&#xff0c;以…

心觉:感恩日记:每天5分钟,重新定义你的人生

​Hi&#xff0c;我是心觉&#xff0c;与你一起玩转潜意识、脑波音乐和吸引力法则&#xff0c;轻松掌控自己的人生&#xff01; 挑战每日一省写作207/1000天 你是否觉得生活节奏太快&#xff0c;总是有做不完的事、解决不完的问题&#xff1f; 有一个简单的方法&#xff0c;…

DEPT_ DECOMPOSED PROMPT TUNING FOR PARAMETER-EFFICIENT FINE-TUNING

论文汇总 当前的问题 (1)Prompt Tuning通常收敛缓慢&#xff0c;并且对初始化敏感&#xff1b; (2)Prompt Tuning延长了输入序列的总长度&#xff0c;从而加剧了计算需求(即训练/推理时间和内存成本)&#xff0c;这是由于Transformer的二次复杂度(Vaswani et al, 2017)。 解…

机器视觉系统硬件组成之工业相机篇

工业相机是一种非常重要的机器视觉器件&#xff0c;它能够将被采集的图像信息通过电路转换成电信号&#xff0c;再通过模数转换器&#xff08;ADC&#xff09;将其转化为数字信号&#xff0c;最后以标准的视频信号输出。工业相机在机器视觉领域得到了广泛应用&#xff0c;包括质…

springboot055服装生产管理的设计与实现(论文+源码)_kaic

毕业设计(论文) 协力服装厂服装生产管理系统 的设计与实现 学生姓名 XXX 学 号 XXXXXXXX 分院名称 XXXXXXXX 专业班级 XXXXX 指导教师 XXXX 填写…

CROss PlatformS (CROPS) 与 Docker

CROPS 是一个开源的、跨平台的开发框架&#xff0c;专为利用 Docker 容器在 Windows、macOS 和 Linux 系统上创建和管理构建主机而设计。它简化了在非 Linux 系统上运行 Yocto 项目及其他基于 Linux 的工具的过程&#xff0c;同时提供了一个可扩展的开发环境&#xff0c;支持多…

基于vue框架的的地铁站智慧管理系统的设计n09jb(程序+源码+数据库+调试部署+开发环境)系统界面在最后面。

系统程序文件列表 项目功能&#xff1a;用户,上班打卡,下班打卡,人员管理,交接班,视频巡检,车辆巡检,车辆管理 开题报告内容 基于Vue框架的地铁站智慧管理系统的设计开题报告 一、研究背景与意义 随着城市化进程的加速&#xff0c;地铁站作为城市交通系统的重要组成部分&am…

全能型选手视频播放器VLC 3.0.21 for Windows 64 bits支持Windows、Mac OS等供大家学习参考

全能型选手视频播放器&#xff0c;支持Windows、Mac OS、Linux、Android、iOS等系统&#xff0c;也支持播放几乎所有主流视频格式。 推荐指数&#xff1a; ★★★★★ 优点&#xff1a; ◆、界面干净简洁&#xff0c;播放流畅 ◆、支持打开绝大多数的文件格式&#xff0c;包…

用Aconvert.com将MOBI文件转换为PDF:一步步指南

在今天的数字时代&#xff0c;文件格式转换是日常办公和学习中常见的需求之一。MOBI格式的电子书文件在某些设备上不太方便阅读&#xff0c;而PDF格式则更加通用。本文将为你详细介绍如何使用Aconvert.com将MOBI文件转换为PDF文件。 1. 访问Aconvert.com 首先&#xff0c;打开…

装修公司行业通用的小程序源码系统 让装修公司实现信息智能化 带完整的安装代码包以及搭建部署教程

系统概述 装修公司行业通用的小程序源码系统是一款专门为装修公司设计的智能化解决方案。它基于先进的技术架构&#xff0c;结合装修行业的特点和需求&#xff0c;为装修公司提供了全方位的业务支持和管理功能。 该系统通过小程序的形式呈现给用户&#xff0c;方便客户随时随…

MacOS13虚拟机VMware Workstation Pro 16安装

资源 安装unlocker 安装虚拟机 低版本的还没有MacOS13选项&#xff0c;这也是我安装低版本虚拟机踩过的坑 找个教程安装就可以了 省略…自己去找找教程… 过程中我使用桥接是不行的&#xff0c;没有网络&#xff0c;后面重新下一步一步的选择默认的网络重装后就好了&am…

基于yolov10的驾驶员抽烟打电话安全带检测系统python源码+pytorch模型+评估指标曲线+精美GUI界面

【算法介绍】 基于YOLOv10的驾驶员抽烟、打电话、安全带检测系统是一种先进的驾驶行为监测系统。该系统利用YOLOv10算法的高效性和准确性&#xff0c;实现对驾驶员行为的实时检测与识别。 YOLOv10是一种最新的实时物体检测模型&#xff0c;其通过深度学习技术&#xff0c;如卷…

如何看ip属于什么地址

在数字化时代&#xff0c;IP地址作为互联网通信的基石&#xff0c;扮演着至关重要的角色。无论是网络管理、安全防护&#xff0c;还是日常的网络访问&#xff0c;理解IP地址的性质和分类都是必不可少的技能。本文将深入探讨如何判断一个IP地址属于哪一类地址&#xff0c;并详细…

Java项目-基于springboot框架的校园医疗保险管理系统项目实战(附源码+文档)

作者&#xff1a;计算机学长阿伟 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、ElementUI等&#xff0c;“文末源码”。 开发运行环境 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringBoot、Vue、Mybaits Plus、ELementUI工具&#xff1a;IDEA/…

Spring Boot整合Stripe订阅支付指南

在当今的在线支付市场中&#xff0c;Stripe 作为一款一体化的全球支付平台&#xff0c;因其易用性和广泛的支付方式支持&#xff0c;得到了许多企业的青睐。本文将详细介绍如何在 Spring Boot 项目中整合 Stripe 实现订阅支付功能。 1.Stripe简介 Stripe 是一家为个人或公司提…

低代码赋能项目管理系统:打造高效协同的数字化工作环境

项目管理是企业日常运营中的重要环节&#xff0c;其运作效率直接关系到项目的成功交付、资源的优化配置及企业的市场竞争力。然而&#xff0c;传统的项目管理系统却面临着诸多挑战。 传统管理系统开发周期长、耗资大、需要大量时间和资源来定制和优化。同时&#xff0c;高昂的维…

K8s-pod详解3(pod调度)

Pod调度 在默认情况下&#xff0c;一个Pod在哪个Node节点上运行&#xff0c;是由Scheduler组件采用相应的算法计算出来的&#xff0c;这个过程是不受人工控制的。但是在实际使用中&#xff0c;这并不满足的需求&#xff0c;因为很多情况下&#xff0c;我们想控制某些Pod到达某…