开启辅助访问 切换到宽版

精易论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

用微信号发送消息登录论坛

新人指南 邀请好友注册 - 我关注人的新帖 教你赚取精币 - 每日签到


求职/招聘- 论坛接单- 开发者大厅

论坛版规 总版规 - 建议/投诉 - 应聘版主 - 精华帖总集 积分说明 - 禁言标准 - 有奖举报

查看: 2177|回复: 29
打印 上一主题 下一主题
收起左侧

[其它源码] 秒杀乐玩极速找图 最新opencv4.11模板匹配 GO开发通用调用API

[复制链接]
结帖率:0% (0/3)
跳转到指定楼层
楼主
发表于 2025-5-27 13:59:48 | 只看该作者 |只看大图 回帖奖励 |正序浏览 |阅读模式   江西省宜春市
分享源码
界面截图:
是否带模块: -
备注说明: -
本帖最后由 callme大大 于 2025-5-27 14:08 编辑

运行效果图:



调用C++编译的DLL 原版 GO多线程加持  带来无与伦比的速度
可以手动测试:http://127.0.0.1:8080/

估计大多数人是无法完成这个opencv的原版编译和调用,众所周知WIN环境下编译gocv的环境搭建非常麻烦,坑巨TM的多。
我这里给出了编译好的包,直接使用即可,不带任何广告。最后附上了源码,想改可以自己改一下。


附上GO源码(用这个源码编译坑多别问懒得回,直接用我编译好的成品):
package main

import (
    "encoding/base64"
    "encoding/json"
    "fmt"
    "gocv.io/x/gocv"
    "html/template"
    "io"
    "log"
    "net/http"
    "strconv"
)

// MatchRequest 请求结构体
type MatchRequest struct {
    BigImage   string  `json:"big_image"`
    SmallImage string  `json:"small_image"`
    MinSim     float64 `json:"min_similarity"`
}

// MatchResponse 响应结构体
type MatchResponse struct {
    Found      bool    `json:"found"`
    X          int     `json:"x"`
    Y          int     `json:"y"`
    Similarity float32 `json:"similarity"`
    Message    string  `json:"message,omitempty"`
}

// decodeBase64Image Base64字符串解码为gocv.Mat
func decodeBase64Image(data string) (gocv.Mat, error) {
    imgBytes, err := base64.StdEncoding.DecodeString(data)
    if err != nil {
       return gocv.NewMat(), fmt.Errorf("Base64解码错误: %v", err)
    }
    mat, err := gocv.IMDecode(imgBytes, gocv.IMReadColor)
    if err != nil {
       return gocv.NewMat(), fmt.Errorf("IMDecode错误: %v", err)
    }
    if mat.Empty() {
       return gocv.NewMat(), fmt.Errorf("解码后的Mat为空")
    }
    return mat, nil
}

// matchHandler 处理匹配请求的HTTP处理函数
func matchHandler(w http.ResponseWriter, r *http.Request) {
    if r.Method != http.MethodPost {
       http.Error(w, "仅支持POST方法", http.StatusMethodNotAllowed)
       return
    }

    var req MatchRequest
    body, err := io.ReadAll(r.Body)
    if err != nil {
       respond(w, false, 0, 0, 0, "读取请求体失败: "+err.Error())
       return
    }
    defer r.Body.Close()

    if err := json.Unmarshal(body, &req); err != nil {
       respond(w, false, 0, 0, 0, "JSON解析失败: "+err.Error())
       return
    }

    minSim := 0.8
    if req.MinSim > 0 && req.MinSim < 1.0 {
       minSim = req.MinSim
    }

    // 解码大图
    bigMat, err := decodeBase64Image(req.BigImage)
    if err != nil {
       respond(w, false, 0, 0, 0, "大图解码失败: "+err.Error())
       return
    }
    defer bigMat.Close()

    // 解码小图
    smallMat, err := decodeBase64Image(req.SmallImage)
    if err != nil {
       respond(w, false, 0, 0, 0, "小图解码失败: "+err.Error())
       return
    }
    defer smallMat.Close()

    // 检查尺寸
    if bigMat.Cols() < smallMat.Cols() || bigMat.Rows() < smallMat.Rows() {
       respond(w, false, 0, 0, 0, "小图尺寸大于大图")
       return
    }

    // 模板匹配
    result := gocv.NewMat()
    defer result.Close()

    gocv.MatchTemplate(bigMat, smallMat, &result, gocv.TmCcoeffNormed, gocv.NewMat())
    _, maxVal, _, maxLoc := gocv.MinMaxLoc(result)

    // 判断是否匹配成功
    if float64(maxVal) >= minSim {
       respond(w, true, maxLoc.X, maxLoc.Y, maxVal, "")
    } else {
       respond(w, false, 0, 0, maxVal, "未找到符合相似度要求的匹配")
    }
}

// respond 统一响应函数
func respond(w http.ResponseWriter, found bool, x, y int, sim float32, msg string) {
    resp := MatchResponse{
       Found:      found,
       X:          x,
       Y:          y,
       Similarity: sim,
       Message:    msg,
    }
    data, err := json.MarshalIndent(resp, "", "  ")
    if err != nil {
       http.Error(w, "响应编码失败: "+err.Error(), http.StatusInternalServerError)
       return
    }
    w.Header().Set("Content-Type", "application/json")
    w.Write(data)
}

// HTML主页模板
const indexHTML = `
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>图片模板匹配测试</title>
<style>
    body { font-family: Arial, sans-serif; margin: 40px; }
    input[type="file"] { margin-bottom: 15px; }
    #resp { width: 100%; height: 180px; }
    .img-preview { max-width: 300px; max-height: 200px; margin: 10px 0; }
</style>
</head>
<body>
<h2>图片模板匹配手动测试</h2>
<form id="form">
    <label>大图: <input type="file" id="big" accept="image/*" required></label><br>
    <img id="bigPreview" class="img-preview"><br>
    <label>小图: <input type="file" id="small" accept="image/*" required></label><br>
    <img id="smallPreview" class="img-preview"><br>
    <label>最小相似度(0~1): <input type="number" id="minSim" step="0.01" value="0.8" min="0" max="1"></label><br><br>
    <button type="submit">查找小图位置</button>
</form>
<br>
<label>接口响应信息:</label><br>
<textarea id="resp" readonly></textarea>

<script>
function fileToBase64(file) {
    return new Promise((resolve, reject) => {
        const reader = new FileReader();
        reader.onload = e => resolve(e.target.result.split(',')[1]);
        reader.onerror = e => reject(e);
        reader.readAsDataURL(file);
    });
}

function showPreview(input, imgId) {
    input.addEventListener('change', function() {
        const file = input.files[0];
        if (file) {
            const url = URL.createObjectURL(file);
            document.getElementById(imgId).src = url;
        }
    });
}
showPreview(document.getElementById('big'), 'bigPreview');
showPreview(document.getElementById('small'), 'smallPreview');

document.getElementById('form').onsubmit = async function(e) {
    e.preventDefault();
    const bigFile = document.getElementById('big').files[0];
    const smallFile = document.getElementById('small').files[0];
    const minSim = parseFloat(document.getElementById('minSim').value);

    if (!bigFile || !smallFile) {
        alert("请上传两张图片");
        return;
    }

    try {
        document.getElementById('resp').value = "图片编码中...";
        const [bigB64, smallB64] = await Promise.all([
            fileToBase64(bigFile),
            fileToBase64(smallFile)
        ]);
        document.getElementById('resp').value = "请求中...";
        const resp = await fetch('/match', {
            method: 'POST',
            headers: {'Content-Type': 'application/json'},
            body: JSON.stringify({
                big_image: bigB64,
                small_image: smallB64,
                min_similarity: minSim
            })
        });
        const text = await resp.text();
        document.getElementById('resp').value = text;
    } catch (err) {
        document.getElementById('resp').value = "请求失败: " + err;
    }
};
</script>
</body>
</html>
`

// indexHandler 返回主页
func indexHandler(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "text/html; charset=utf-8")
    tmpl := template.Must(template.New("index").Parse(indexHTML))
    tmpl.Execute(w, nil)
}

func main() {
    http.HandleFunc("/", indexHandler)
    http.HandleFunc("/match", matchHandler)
    port := 8080
    log.Printf("服务启动,监听端口: %d", port)
    log.Fatal(http.ListenAndServe(":"+strconv.Itoa(port), nil))
}





这里下载完整的编译好的:

通过网盘分享的文件:GO_opencv找图.rar
链接: https://pan.baidu.com/s/19Dm3r7eidWu5XxulQoTAKw 提取码: schm
--来自百度网盘超级会员v7的分享
使用方法:使用post直接本地调用api 传json数据。


地址:http://127.0.0.1:8080/match

图片要base64编码传输。注意自己传数据,简易用e2ee
{
  "big_image": "(大图的Base64字符串)",
  "small_image": "(小图的Base64字符串)",
  "min_similarity": 0.8
}

















点评

端口可以修改吗?能不能搞一个易语言的服务端   四川省*  发表于 2025-6-21 12:39

结帖率:0% (0/3)
29
 楼主| 发表于 2025-6-22 15:49:50 | 只看该作者   江西省宜春市
kiss0459 发表于 2025-5-29 23:42
为啥不直接调用dll,非要搞web服务呢,web服务调用速度比直接调用dll快?

可以本地调用啊
回复 支持 反对

使用道具 举报

结帖率:11% (2/18)

签到天数: 6 天

28
发表于 2025-6-21 12:39:42 | 只看该作者   四川省*
端口可以修改吗?能不能搞一个易语言的服务端
回复 支持 反对

使用道具 举报

结帖率:0% (0/2)

签到天数: 4 天

27
发表于 2025-6-8 00:09:11 | 只看该作者   广东省深圳市
66666666666666
回复 支持 反对

使用道具 举报

结帖率:0% (0/1)

签到天数: 5 天

26
发表于 2025-6-7 21:32:19 | 只看该作者   江苏省苏州市
6666666666666666666666666666
回复 支持 反对

使用道具 举报

签到天数: 4 天

25
发表于 2025-6-2 11:34:45 | 只看该作者   重庆市重庆市
有例子吗
回复 支持 反对

使用道具 举报

签到天数: 6 天

24
发表于 2025-5-30 20:47:00 | 只看该作者   北京市北京市
网络通信不说识别速度,光是转base64再传输,人家调用dll的结果图都绘完了
回复 支持 反对

使用道具 举报

结帖率:25% (6/24)

签到天数: 4 天

23
发表于 2025-5-29 23:42:54 | 只看该作者   黑龙江省大庆市
为啥不直接调用dll,非要搞web服务呢,web服务调用速度比直接调用dll快?
回复 支持 反对

使用道具 举报

签到天数: 4 天

22
发表于 2025-5-29 17:28:53 | 只看该作者   重庆市重庆市
我也来试试看
回复 支持 反对

使用道具 举报

结帖率:86% (6/7)

签到天数: 1 天

21
发表于 2025-5-28 14:49:47 | 只看该作者   河北省唐山市
端口可以修改吗》?
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则 致发广告者

发布主题 收藏帖子 返回列表

sitemap| 易语言源码| 易语言教程| 易语言论坛| 易语言模块| 手机版| 广告投放| 精易论坛
拒绝任何人以任何形式在本论坛发表与中华人民共和国法律相抵触的言论,本站内容均为会员发表,并不代表精易立场!
论坛帖子内容仅用于技术交流学习和研究的目的,严禁用于非法目的,否则造成一切后果自负!如帖子内容侵害到你的权益,请联系我们!
防范网络诈骗,远离网络犯罪 违法和不良信息举报QQ: 793400750,邮箱:[email protected]
网站简介:精易论坛成立于2009年,是一个程序设计学习交流技术论坛,隶属于揭阳市揭东区精易科技有限公司所有。
Powered by Discuz! X3.4 揭阳市揭东区精易科技有限公司 ( 粤ICP备12094385号-1) 粤公网安备 44522102000125 增值电信业务经营许可证 粤B2-20192173

快速回复 返回顶部 返回列表