Java调用Pytorch实现以图搜图(附源码)
Java调用Pytorch实现以图搜图
设计技术栈:
1、ElasticSearch环境;
2、Python运行环境(如果事先没有pytorch模型时,可以用python脚本创建模型);
1、运行效果

2、创建模型(有则可以跳过)
vi script.py
import torch
import torch.nn as nn
import torchvision.models as modelsclass ImageFeatureExtractor(nn.Module):def __init__(self):super(ImageFeatureExtractor, self).__init__()self.resnet = models.resnet50(pretrained=True)#最终输出维度1024的向量,下文elastic search要设置dims为1024self.resnet.fc = nn.Linear(2048, 1024)def forward(self, x):x = self.resnet(x)return xif __name__ == '__main__':model = ImageFeatureExtractor()model.eval()#根据模型随便创建一个输入input = torch.rand([1, 3, 224, 224])output = model(input)#以这种方式保存script = torch.jit.trace(model, input)script.save("model.pt")
2、java项目pom.xml
<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><scope>provided</scope></dependency><dependency><groupId>ai.djl.pytorch</groupId><artifactId>pytorch-engine</artifactId><version>0.19.0</version></dependency><dependency><groupId>ai.djl.pytorch</groupId><artifactId>pytorch-native-cpu</artifactId><version>1.10.0</version><scope>runtime</scope></dependency><dependency><groupId>ai.djl.pytorch</groupId><artifactId>pytorch-jni</artifactId><version>1.10.0-0.19.0</version></dependency><dependency><groupId>org.elasticsearch.client</groupId><artifactId>elasticsearch-rest-high-level-client</artifactId></dependency></dependencies>
3、ES创建文档
PUT /isi
{"mappings": {"properties": {"vector": {"type": "dense_vector","dims": 1024},"url" : {"type" : "keyword"},"user_id": {"type": "keyword"}}}
}
4、编写java代码调用模型
ORCUtil.java
package com.topprismcloud.rtm;import ai.djl.Device;
import ai.djl.Model;
import ai.djl.inference.Predictor;
import ai.djl.modality.cv.Image;
import ai.djl.modality.cv.ImageFactory;
import ai.djl.modality.cv.transform.Normalize;
import ai.djl.modality.cv.transform.Resize;
import ai.djl.modality.cv.transform.ToTensor;
import ai.djl.modality.cv.util.NDImageUtils;
import ai.djl.ndarray.NDArray;
import ai.djl.ndarray.NDList;
import ai.djl.ndarray.NDManager;
import ai.djl.translate.Transform;
import ai.djl.translate.Translator;
import ai.djl.translate.TranslatorContext;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.ScriptQueryBuilder;
import org.elasticsearch.index.query.functionscore.FunctionScoreQueryBuilder;
import org.elasticsearch.index.query.functionscore.ScoreFunctionBuilders;
import org.elasticsearch.script.Script;
import org.elasticsearch.script.ScriptType;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.xcontent.XContentType;import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URL;
import java.nio.file.Paths;
import java.util.*;public class ORCUtil {private static final String INDEX = "isi";private static final int IMAGE_SIZE = 224;private static Model model; // 模型private static Predictor<Image, float[]> predictor; // predictor.predict(input)相当于python中model(input)static {try {model = Model.newInstance("model");// 这里的model.pt是上面代码展示的那种方式保存的model.load(ORCUtil.class.getClassLoader().getResourceAsStream("model.pt"));Transform resize = new Resize(IMAGE_SIZE);Transform toTensor = new ToTensor();Transform normalize = new Normalize(new float[] { 0.485f, 0.456f, 0.406f },new float[] { 0.229f, 0.224f, 0.225f });// Translator处理输入Image转为tensor、输出转为float[]Translator<Image, float[]> translator = new Translator<Image, float[]>() {@Overridepublic NDList processInput(TranslatorContext ctx, Image input) throws Exception {NDManager ndManager = ctx.getNDManager();System.out.println("input: " + input.getWidth() + ", " + input.getHeight());NDArray transform = normalize.transform(toTensor.transform(resize.transform(input.toNDArray(ndManager))));System.out.println(transform.getShape());NDList list = new NDList();list.add(transform);return list;}@Overridepublic float[] processOutput(TranslatorContext ctx, NDList ndList) throws Exception {return ndList.get(0).toFloatArray();}};predictor = new Predictor<>(model, translator, Device.cpu(), true);} catch (Exception e) {e.printStackTrace();}}public static void upload() throws Exception {HttpHost host=new HttpHost("14.20.30.16", 9200, HttpHost.DEFAULT_SCHEME_NAME);RestClientBuilder builder=RestClient.builder(host);CredentialsProvider credentialsProvider = new BasicCredentialsProvider();credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials("elastic", "123456"));builder.setHttpClientConfigCallback(f -> f.setDefaultCredentialsProvider(credentialsProvider));RestHighLevelClient client = new RestHighLevelClient( builder);// 批量上传请求BulkRequest bulkRequest = new BulkRequest(INDEX);File file = new File("D:\\001ENV\\nginx-1.24.0\\html\\resource\\new");for (File listFile : file.listFiles()) {
// float[] vector = predictor.predict(ImageFactory.getInstance()
// .fromInputStream(Test.class.getClassLoader().getResourceAsStream("new/" + listFile.getName())));float[] vector = predictor.predict(ImageFactory.getInstance().fromInputStream(new FileInputStream(listFile)));// 构建文档Map<String, Object> jsonMap = new HashMap<>();jsonMap.put("url", "/resource/"+listFile.getName());jsonMap.put("vector", vector);jsonMap.put("user_id", "user123");IndexRequest request = new IndexRequest(INDEX).source(jsonMap, XContentType.JSON);bulkRequest.add(request);}client.bulk(bulkRequest, RequestOptions.DEFAULT);client.close();}// 接收待搜索图片的inputstream,搜索与其相似的图片public static List<SearchResult> search(InputStream input) throws Throwable {float[] vector = predictor.predict(ImageFactory.getInstance().fromInputStream(input));System.out.println(Arrays.toString(vector));// 展示k个结果int k = 100;// 连接Elasticsearch服务器RestHighLevelClient client = new RestHighLevelClient(RestClient.builder(new HttpHost("14.20.30.16", 9200, "http")));SearchRequest searchRequest = new SearchRequest(INDEX);Script script = new Script(ScriptType.INLINE, "painless", "cosineSimilarity(params.queryVector, doc['vector'])",Collections.singletonMap("queryVector", vector));FunctionScoreQueryBuilder functionScoreQueryBuilder = QueryBuilders.functionScoreQuery(QueryBuilders.matchAllQuery(), ScoreFunctionBuilders.scriptFunction(script));SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();searchSourceBuilder.query(functionScoreQueryBuilder).fetchSource(null, "vector") // 不返回vector字段,太多了没用还耗时.size(k);searchRequest.source(searchSourceBuilder);SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);SearchHits hits = searchResponse.getHits();List<SearchResult> list = new ArrayList<>();for (SearchHit hit : hits) {// 处理搜索结果System.out.println(hit.toString());SearchResult result = new SearchResult((String) hit.getSourceAsMap().get("url"), hit.getScore());list.add(result);}client.close();return list;}public static void main(String[] args) throws Throwable {ORCUtil.upload();System.out.println("hao");}
}
SearchController.java
package com.topprismcloud.rtm;import java.util.List;import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;@RestController
@CrossOrigin
public class SearchController {@PostMapping("search")public ResponseEntity search(MultipartFile file) {try {List<SearchResult> list = ORCUtil.search(file.getInputStream());return ResponseEntity.ok(list);} catch (Throwable e) {return ResponseEntity.status(400).body(null);}}
}
SearchResult.java
package com.topprismcloud.rtm;import lombok.AllArgsConstructor;
import lombok.Data;@Data
@AllArgsConstructor
public class SearchResult {private String url;private Float score;
}
5、前端
index.html
<!DOCTYPE html>
<html lang="zh"><head><meta charset="UTF-8"><title>以图搜图</title><style>body {background: url("/img/bg.jpg");background-attachment: fixed;background-size: 100% 100%;}body>div {width: 1000px;margin: 50px auto;padding: 10px 20px;border: 1px solid lightgray;border-radius: 20px;box-sizing: border-box;background: rgba(255, 255, 255, 0.7);}.upload {display: inline-block;width: 300px;height: 280px;border: 1px dashed lightcoral;vertical-align: top;}.upload .cover {width: 200px;height: 200px;margin: 10px 50px;border: 1px solid black;box-sizing: border-box;text-align: center;line-height: 200px;position: relative;}.upload img {width: 198px;height: 198px;position: absolute;left: 0;top: 0;}.upload input {margin-left: 50px;}.upload button {width: 80px;height: 30px;margin-left: 110px;}.result-block {display: inline-block;margin-left: 40px;border: 1px solid lightgray;border-radius: 10px;min-height: 500px;width: 600px;}.result-block h1 {text-align: center;margin-top: 100px;}.result {padding: 10px;cursor: pointer;display: inline-block;}.result:hover {background: rgb(240, 240, 240);}.result p {width: 110px;overflow: hidden;white-space: nowrap;text-overflow: ellipsis;}.result img {width: 160px;height: 160px;}.result .prob {color: rgb(37, 147, 60)}</style><script src="js/jquery-3.6.0.js"></script>
</head><body><div><div class="upload"><div class="cover">请选择图片<img id="image" src="" /></div><input id="file" type="file"></div><div class="result-block"><h1>请选择图片</h1></div></div><ul id="box"></ul><script>var file = $('#file')file.change(function () {let f = this.files[0]let index = f.name.lastIndexOf('.')let fileText = f.name.substring(index, f.name.length)let ext = fileText.toLowerCase() //文件类型console.log(ext)if (ext != '.png' && ext != '.jpg' && ext != '.jpeg') {alert('系统仅支持 JPG、PNG、JPEG 格式的图片,请您调整格式后重新上传')return}$('.result-block').empty().append($('<h1>正在识别中...</h1>'))$("#image").attr("src", getObjectURL(f));let formData = new FormData()formData.append('file', f)$.ajax({url: 'http://10.1.2.240:8081/search',method: 'post',data: formData,processData: false,contentType: false,success: res => {console.log('shibie', res)$('.result-block').empty()for (let item of res) {console.log(item)let html = `<div class="result"><img src="${item.url}"/><div style="display: inline-block;vertical-align: top"><p class="prob">得分:${item.score.toFixed(4)}</p></div></div>`$('.result-block').append($(html))}}})});$('#button').click(function (e) {var file = $('#file')[0].files[0] //单个console.log(file)})function getObjectURL(file) {var url = null;if (window.createObjcectURL != undefined) {url = window.createOjcectURL(file);} else if (window.URL != undefined) {url = window.URL.createObjectURL(file);} else if (window.webkitURL != undefined) {url = window.webkitURL.createObjectURL(file);}return url;}function detect() {}</script>
</body></html>
6、打包后的源代码
以图搜图Java+html源代码
相关参考文章:Java调用Pytorch模型进行图像识别
相关文章:
Java调用Pytorch实现以图搜图(附源码)
Java调用Pytorch实现以图搜图 设计技术栈: 1、ElasticSearch环境; 2、Python运行环境(如果事先没有pytorch模型时,可以用python脚本创建模型); 1、运行效果 2、创建模型(有则可以跳过…...
【EasyX】实时时钟
目录 实时时钟1. 绘制静态秒针2. 秒针的转动3. 根据实际时间转动4. 添加时针和分针5. 添加表盘刻度 实时时钟 本博客介绍利用EasyX实现一个实时钟表的小程序,同时学习时间函数的使用。 本文源码可从github获取 1. 绘制静态秒针 第一步定义钟表的中心坐标center&a…...
基于XC7Z100的PCIe采集卡(GMSL FMC采集卡)
GMSL 图像采集卡 特性 ● PCIe Gen2.0 X8 总线; ● 支持V4L2调用; ● 1路CAN接口; ● 6路/12路 GMSL1/2摄像头输入,最高可达8MP; ● 2路可定义相机同步触发输入/输出; 优势 ● 采用PCIe主卡与FMC子…...
Kibana:使用 Kibana 自带数据进行可视化(一)
在今天的练习中,我们将使用 Kibana 自带的数据来进行一些可视化的展示。希望对刚开始使用 Kibana 的用户有所帮助。 前提条件 如果你还没有安装好自己的 Elastic Stack,你可以参考如下的视频来开启 Elastic Stack 并进行下面的练习。你可以开通阿里云检…...
MySQL数据库基础 07
第七章 单行函数 1. 函数的理解1.1 什么是函数1.2 不同DBMS函数的差异1.3 MySQL的内置函数及分类 2. 数值函数2.1 基本函数2.2 角度与弧度互换函数2.3 三角函数2.4 指数与对数2.5 进制间的转换 3. 字符串函数4. 日期和时间函数4.1 获取日期、时间 4.2 日期与时间戳的转换 4.3 获…...
JVM | JVM垃圾回收
JVM | JVM垃圾回收 1、堆空间的基本结构2、内存分配和回收原则2.1、对象优先在 Eden 区分配2.2、大对象直接进入老年代2.3、长期存活的对象将进入老年代2.4、主要进行 gc 的区域2.5、空间分配担保3、死亡对象判断方法3.1、引用计数法3.2、可达性分析算法3.3、引用类型总结3.4、…...
avive零头撸矿
Avive 是一个透明的、自下而上替代自上而下的多元网络,旨在克服当前生态系统的局限性,实现去中心化社会。 aVive:一个基于 SBT 和市场的 deSoc,它使 dapps 能够与分散的位置 oracle 和 SBT 关系进行互操作。您的主权社交网络元宇宙…...
openGauss5.0之学习环境 Docker安装
文章目录 0.前言1. 准备软硬件安装环境1.1 软硬件环境要求1.2 修改操作系统配置1.2.1 关闭操作系统防火墙 1.3 设置字符集参数1.4 设置时区和时间(可选)关闭swap交换内存1.5 关闭RemoveIPC1.6 关闭HISTORY记录 2. 容器安装2. 1支持的架构和操作系统版本2…...
数据可视化大屏人员停留系统的开发实录(默认加载条件筛选、单击加载、自动刷新加载、异步加载数据)
项目需求 录入进入房间的相关数据;从进入时间开始计时,计算滞留房间的时间;定时刷新数据,超过30分钟的人数,进行红色告警; 实现流程 为了完整地实现上述需求,我们可以按照以下步骤开发&#…...
【Linux】-关于调试器gdb的介绍和使用
作者:小树苗渴望变成参天大树 作者宣言:认真写好每一篇博客 作者gitee:gitee 如 果 你 喜 欢 作 者 的 文 章 ,就 给 作 者 点 点 关 注 吧! 文章目录 前言一、Linux中的debug和release二、gdb的使用**1.进入调试****2.显示代码*…...
项目开发经验
hadoop 1.namenode中有专门的工作线程池用于处理与datanode的心跳信号 dfs.namenode.handler.count20 * log2(Clust 2.编辑日志存储路径 dfs.namenode.edits.dir 设置与镜像文件存储路径 dfs.namenode分开存放,可以达到提高并发 3.yarn参数调优,单个服…...
STM32——05-按键、时钟控制、中断复位 点亮LED灯
如何点亮一颗LED灯 编程实现点灯 常用的 GPIO HAL 库函数: void HAL_GPIO_Init ( GPIO_TypeDef * GPIOx , GPIO_InitTypeDef * GPIO_Init ); void HAL_GPIO_WritePin ( GPIO_TypeDef * GPIOx , uint16_t GPIO_Pin , GPIO_PinState PinState ); void HAL_GPIO_Togg…...
VBA下载二进制文件,文本读写
这里使用了vba如下两个对象: Microsoft.XMLHTTP:文件读写,可读写二进制,可指定编码,对于utf-8编码文本文件使用FSO的TextStream对象打开,读取到的内容可能会出现乱码,可以使用该对象打开;前期绑定添加引用…...
MongoDB结合Robo 3T 1.4.3的简单操作
MongoDB的简单操作结合Robo 3T 1.4.3工具进行查询。 常用的正则表达式 /* 29 */ 正则表达式 /\* [0-9]* \*/ "_id" : ObjectId("5f3d05cdfd2aa9a8a7"), 正则表达式 \"([^\"]*_id)\".*, 使用方法:查询结果去掉注释和不需要…...
【学习笔记】[AGC048D] Pocky Game
这是一个非平等博弈。但是只要求你判断胜负,本身也不是一道结论题,所以可以用 D P DP DP来解决。 结论:第一堆石子剩的越多,先手玩家获胜的概率越大。这直接引出了一个非常感性的结论:每次取石子时要么取一堆…...
Qgis中进行Shp和Excel属性连接实现百强县公共预算空间分析
前言 在之前的博文中,将2022的全国百强县一般公共预算收入的数据下载到了本地,博客原文地址:一种使用Java的快速将Web中表格转换成Excel的方法。对于不关注时空位置关系的一般分析,到此也就基本够用了。但是,如果站在全…...
ES6 新增的循环方法
在 ES6(ECMAScript 2015)中,新增了一些循环方法,这些方法可以帮助我们更方便地遍历数组、字符串、Set、Map 等数据结构。本文将介绍一些常用的 ES6 循环方法。 for…of 循环 for…of 循环是一种遍历可迭代对象的方法,…...
移动端事件300ms延迟解决
有移动端与PC端的项目开发,那么移动端和PC端开发上是存在差异的,比如 click 事件的300ms 延迟,即移动Web页面上的click事件响应都要慢上300ms,移动设备访问Web页面时往往需要 “双击” 或者 “捏开” 来放大页面看清页面的具体内容…...
NRF52832的DFU
开发环境: Winsodw:10 nRF5_SDK:17.1.0 1 工具安装 1.1 gcc-arm-none-eabi Downloads | GNU Arm Embedded Toolchain Downloads – Arm Developer 下载“gcc-arm-none-eabi-10.3-2021.10-win32.exe”,接提示安装。注意安装完…...
开源WebRTC库放大器模式在采集桌面图像时遇到的DPI缩放与内存泄漏问题排查
目录 1、在非100%的显示比例下放大器采集到的桌面图像不全问题 1.1、通过manifest文件禁止系统对软件进行缩放 1.2、调用SetThreadDpiAwarenessContext函数,禁止系统对目标线程中的窗口进行缩放 1.3、使用winver命令查看Windows的年月版本 2、使用放大器模式遇…...
测试微信模版消息推送
进入“开发接口管理”--“公众平台测试账号”,无需申请公众账号、可在测试账号中体验并测试微信公众平台所有高级接口。 获取access_token: 自定义模版消息: 关注测试号:扫二维码关注测试号。 发送模版消息: import requests da…...
从零实现富文本编辑器#5-编辑器选区模型的状态结构表达
先前我们总结了浏览器选区模型的交互策略,并且实现了基本的选区操作,还调研了自绘选区的实现。那么相对的,我们还需要设计编辑器的选区表达,也可以称为模型选区。编辑器中应用变更时的操作范围,就是以模型选区为基准来…...
【Java学习笔记】Arrays类
Arrays 类 1. 导入包:import java.util.Arrays 2. 常用方法一览表 方法描述Arrays.toString()返回数组的字符串形式Arrays.sort()排序(自然排序和定制排序)Arrays.binarySearch()通过二分搜索法进行查找(前提:数组是…...
C++.OpenGL (10/64)基础光照(Basic Lighting)
基础光照(Basic Lighting) 冯氏光照模型(Phong Lighting Model) #mermaid-svg-GLdskXwWINxNGHso {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-GLdskXwWINxNGHso .error-icon{fill:#552222;}#mermaid-svg-GLd…...
优选算法第十二讲:队列 + 宽搜 优先级队列
优选算法第十二讲:队列 宽搜 && 优先级队列 1.N叉树的层序遍历2.二叉树的锯齿型层序遍历3.二叉树最大宽度4.在每个树行中找最大值5.优先级队列 -- 最后一块石头的重量6.数据流中的第K大元素7.前K个高频单词8.数据流的中位数 1.N叉树的层序遍历 2.二叉树的锯…...
使用 SymPy 进行向量和矩阵的高级操作
在科学计算和工程领域,向量和矩阵操作是解决问题的核心技能之一。Python 的 SymPy 库提供了强大的符号计算功能,能够高效地处理向量和矩阵的各种操作。本文将深入探讨如何使用 SymPy 进行向量和矩阵的创建、合并以及维度拓展等操作,并通过具体…...
代理篇12|深入理解 Vite中的Proxy接口代理配置
在前端开发中,常常会遇到 跨域请求接口 的情况。为了解决这个问题,Vite 和 Webpack 都提供了 proxy 代理功能,用于将本地开发请求转发到后端服务器。 什么是代理(proxy)? 代理是在开发过程中,前端项目通过开发服务器,将指定的请求“转发”到真实的后端服务器,从而绕…...
Redis的发布订阅模式与专业的 MQ(如 Kafka, RabbitMQ)相比,优缺点是什么?适用于哪些场景?
Redis 的发布订阅(Pub/Sub)模式与专业的 MQ(Message Queue)如 Kafka、RabbitMQ 进行比较,核心的权衡点在于:简单与速度 vs. 可靠与功能。 下面我们详细展开对比。 Redis Pub/Sub 的核心特点 它是一个发后…...
基于 TAPD 进行项目管理
起因 自己写了个小工具,仓库用的Github。之前在用markdown进行需求管理,现在随着功能的增加,感觉有点难以管理了,所以用TAPD这个工具进行需求、Bug管理。 操作流程 注册 TAPD,需要提供一个企业名新建一个项目&#…...
Java求职者面试指南:计算机基础与源码原理深度解析
Java求职者面试指南:计算机基础与源码原理深度解析 第一轮提问:基础概念问题 1. 请解释什么是进程和线程的区别? 面试官:进程是程序的一次执行过程,是系统进行资源分配和调度的基本单位;而线程是进程中的…...
