VisionMaster集成深度学习算法(基础狗)

VisionMaster集成深度学习算法(基础狗)

1.首先要有基础狗,能正常打开VM

2.要有一个模型 不管是yolo还是其他,实在不行去看我上一篇文章 而且模型是onnx格式,如果是英伟达的显卡,也可以tensorRT,个人理解,只要是C++ VS能正常调用起来就行

我后面的例子是 YOLO 分割 + 无监督深度学习两个模型的组合,得到两个模型

3.了解VisionMaster 加入自己模块的方法

3.1 先看下VisionMaster自己的工程

cpp 复制代码
**VisionMaster4.4.0\Applications\Tools
上面这个路径下存了他们自己的例子
**VisionMaster4.4.0\Applications\Tools\AlgorithmXMLGenerator
这个地方是xml生成器 还有 demo 
AlgorithmXMLGenerator.exe 
这个插件可以直接生成一堆xml,主要是和VM进行数据交互
也可以生成C++工程 C++工程主要是进行二次开发 或者 进行深度学习推理

3.2 先简单介绍下这个官方软件

第一步:先定义输入输出 比如复选框 输入影像 位置修正信息 / 模型状态 输出图像,这些是为了和上下模块间进行数据交互的

2.定义运行参数 就是我们算法需要提供给外部的接口 调参用

3.生成接口文件 xml 和 C++工程 后面打开开发即可

4.开始详细介绍:

4.1 先准备好自己的深度学习 推理C++调用脚本 这个默认大家是会的

4.2 先介绍下各个xml是代表什么意思

如我新建的工程:

(1) 最主要的是 PatchCoreYoloModuCs.dll 这个是和VM交互的C#程序

在这个路径下的工程查看

cpp 复制代码
**VisionMaster4.4.0\Applications\Tools\AlgorithmXMLGenerator\project\VM431\ExampleModuCs\ExampleModuCs

(2)PatchCoreYoloModu.dll 这个是自己的C++动态库 推理使用

(3)这些XML文件代表什么意思,从上面这个工程里面的例子可以看出来

cpp 复制代码
Applications\Module(sp)\x64\UserTools\PatchCoreYoloModu\
├── PatchCoreYoloModu.dll            C++ 算法层(必须)
├── PatchCoreYoloModuCs.dll          C# 模块句柄
├── PatchCoreYoloModuControl.dll     C# 参数面板
├── PatchCoreYoloModu.xml            端口契约(必须)
├── PatchCoreYoloModuAlgorithm.xml   参数存储(必须)
├── PatchCoreYoloModuAlgorithmTab.xml 参数界面(必须)
├── PatchCoreYoloModuDisplay.xml     渲染配置(必须)
├── ToolItemInfo.xml                 工具箱条目(必须)
├── PatchCoreYoloModuImageEnable.png 启用图标
├── PatchCoreYoloModu_NormalLogo.png 正常图标
├── PatchCoreYoloModu_StateLogo.png  状态图标
├── App.ini                          可选
└── *.pdb                            调试用,可留

(4)还有个问题 就是你看下面所有的前缀都是一样的,不知道为什么这样拖到VM中,插件显示不了中文,所以如果对中文要求比较高,所有前面都可以换成中文

(5)编译完的工程可以放到这个路径下

cpp 复制代码
**VisionMaster4.4.0\Applications\Module(sp)\x64

4.3 开始看C#工程

其实只需要一个就行 注册一下模块名称和参数内容 字段要一致

另外一个是自己写的界面嵌入 这里不介绍 我也不会 dll直接缺省也可以

4.4 看C++工程

common 是VM的第三方库

输出的dll名称要和xml前缀一致 也可以搞成中文

下来就是一堆包含目录和库目录

需要有一个.h 和 .cpp 支持dll导出

下面这四个对外接口是要有的

cpp 复制代码
int Init();
int Process(IN void* hInput, IN void* hOutput, IN MVDSDK_BASE_MODU_INPUT* modu_input);
int GetParam(IN const char* szParamName, OUT char* pBuff, IN int nBuffSize, OUT int* pDataLen);
int SetParam(IN const char* szParamName, IN const char* pData, IN int nDataLen);
cpp 复制代码
#pragma once

#ifdef PATCHCOREYOLOMODULE_EXPORTS
#define PATCHCOREYOLO_API __declspec(dllexport)
#else
#define PATCHCOREYOLO_API __declspec(dllimport)
#endif

#include "VmModuleBase.h"
#include "VmAlgModuBase.h"
#include "ErrorCodeDefine.h"

// 你现有工程的推理类,直接复用,不做任何修改
#include "inferencer.h"
#include "TileStitcher.h"
#include "YoloSegInferencer.h"

#include <string>
#include <memory>

/// 输出图类型,和 AlgorithmTab.xml 里 OutputImageType 的 EnumEntry Value 对应
enum OutputImageType
{
    OUT_IMG_OVERLAY   = 1,
    OUT_IMG_HEATMAP   = 2,
    OUT_IMG_PRED_MASK = 3,
    OUT_IMG_YOLO_MASK = 4
};

class PATCHCOREYOLO_API CAlgorithmModule
    : public CVmAlgModuleBase
{
public:
    explicit CAlgorithmModule();
    virtual ~CAlgorithmModule();

    int Init();
    int Process(IN void* hInput, IN void* hOutput, IN MVDSDK_BASE_MODU_INPUT* modu_input);
    int GetParam(IN const char* szParamName, OUT char* pBuff, IN int nBuffSize, OUT int* pDataLen);
    int SetParam(IN const char* szParamName, IN const char* pData, IN int nDataLen);

private:
    // ---------- 模型管理 ----------
    /// 按 m_patchCorePath 重新构造 Inferencer。失败时 m_inferencer 置空并写 m_lastError。
    bool ReloadPatchCore();
    /// 按 m_yoloPath 重新构造 YoloSegInferencer。
    bool ReloadYolo();
    /// 用一张全黑图跑一次推理,把 TensorRT/cuDNN 的首次构图开销挪到加载阶段
    void WarmUp();

    // ---------- 图像转换 ----------
    /// HKA_IMAGE -> BGR cv::Mat。只支持 MONO8 和 RGB24(VM 输入端仅产出这两种)。
    static bool HkaImageToMat(const HKA_IMAGE& src, cv::Mat& dst);
    /// BGR cv::Mat -> 共享内存 + VM 输出。内部会转成 RGB,因为 VM 输出端固定按 RGB 解释。
    int OutputMat(void* hOutput, const cv::Mat& mat);

    // ---------- 结果统计 ----------
    /// 从 pred_mask 数连通域,返回缺陷数,并把总面积写进 totalArea
    static int CountDefects(const cv::Mat& predMask, double& totalArea);

private:
    // ====== 参数(由 SetParam 从界面收到)======
    std::string m_patchCorePath;
    std::string m_yoloPath;

    int    m_tileSize;
    int    m_overlap;
    int    m_minMaskPixels;

    double m_pixelThreshold;
    double m_minArea;
    int    m_contourWidth;

    float  m_scoreThreshold;
    float  m_inferPixelThreshold;

    float  m_yoloConf;
    float  m_yoloIou;

    int    m_outputImageType;
    bool   m_warmUpEnable;

    // ====== 运行时状态 ======
    std::unique_ptr<Inferencer>        m_inferencer;
    std::unique_ptr<YoloSegInferencer> m_yolo;

    std::string m_modelStatus;   ///< 供 GetParam("ModelStatus") 回给界面
    std::string m_execProvider;  ///< "GPU" / "CPU" / ""
    std::string m_lastError;

    // [FIX-OutImage] VM4.4 输出图像必须走 VM_M_SetImageEx 并携带共享内存名;
    // 共享块取自输入图像(VM_M_GetImageEx 返回 pImgData + chSharedMemoryName),
    // 输出数据 memcpy 进该共享块后用浅拷贝注册,渲染控件只显示共享内存中的图像。
    char           m_strInShmName[SHARED_MEM_NAME_LEN];
    unsigned char* m_pInShmData;   ///< 输入共享块的数据指针(输出数据写到这里)
    int            m_nInShmLen;    ///< 输入共享块容量(字节)
};

/////////////////////////// 模块须导出的接口 ///////////////////////////
#ifdef __cplusplus
extern "C" {
#endif

    PATCHCOREYOLO_API CAbstractUserModule* __stdcall CreateModule(void* hModule);
    PATCHCOREYOLO_API void __stdcall DestroyModule(void* hModule, CAbstractUserModule* pUserModule);

#ifdef __cplusplus
};
#endif
cpp 复制代码
#include "stdafx.h"
#include "PatchCoreYoloModu.h"
#include "iMVS-6000PixelFormatDefine.h"

#include <stdlib.h>
#include <string.h>
#include <chrono>

// ============================================================================
// 小工具
// ============================================================================

/// UTF-8 / ANSI 窄字符串 -> 宽字符串。Inferencer 的构造函数要 wchar_t*。
/// VM 界面传下来的路径是 UTF-8,含中文目录时必须按 UTF-8 解码,否则模型打不开。
static std::wstring Utf8ToWString(const std::string& s)
{
    if (s.empty()) return std::wstring();

    int n = ::MultiByteToWideChar(CP_UTF8, 0, s.c_str(), (int)s.size(), NULL, 0);
    if (n <= 0)
    {
        // 不是合法 UTF-8,退回按本地代码页解释
        n = ::MultiByteToWideChar(CP_ACP, 0, s.c_str(), (int)s.size(), NULL, 0);
        if (n <= 0) return std::wstring();
        std::wstring w(n, L'\0');
        ::MultiByteToWideChar(CP_ACP, 0, s.c_str(), (int)s.size(), &w[0], n);
        return w;
    }
    std::wstring w(n, L'\0');
    ::MultiByteToWideChar(CP_UTF8, 0, s.c_str(), (int)s.size(), &w[0], n);
    return w;
}

/// 把字符串安全拷进 GetParam 的输出缓冲
static int FillOutBuffer(const std::string& src, char* pBuff, int nBuffSize, int* pDataLen)
{
    int len = (int)src.size();
    if (len + 1 > nBuffSize) len = nBuffSize - 1;
    if (len < 0) return IMVS_EC_PARAM;

    memcpy(pBuff, src.c_str(), len);
    pBuff[len] = '\0';
    *pDataLen = len;
    return IMVS_EC_OK;
}

// ============================================================================
// 构造 / 析构 / Init
// ============================================================================

CAlgorithmModule::CAlgorithmModule()
    : m_tileSize(1024)
    , m_overlap(256)
    , m_minMaskPixels(5000)
    , m_pixelThreshold(0.2)
    , m_minArea(800.0)
    , m_contourWidth(2)
    , m_scoreThreshold(0.5f)
    , m_inferPixelThreshold(0.4f)
    , m_yoloConf(0.5f)
    , m_yoloIou(0.6f)
    , m_outputImageType(OUT_IMG_OVERLAY)
    , m_warmUpEnable(true)
    , m_modelStatus("未加载")
    , m_pInShmData(NULL)
    , m_nInShmLen(0)
{
    m_strInShmName[0] = '\0';
}

CAlgorithmModule::~CAlgorithmModule()
{
}

int CAlgorithmModule::Init()
{
    int nRet = VM_M_GetModuleId(m_hModule, &m_nModuleId);
    if (IMVS_EC_OK != nRet)
    {
        m_nModuleId = -1;
        return nRet;
    }

    // 把 PatchCoreYoloModuAlgorithm.xml 里的 DefaultValue 逐个回灌到 SetParam。
    // 模型路径此时为空,真正的加载发生在界面选好文件后的那次 SetParam。
    nRet = ResetDefaultParam();
    if (nRet != IMVS_EC_OK)
    {
        OutputDebugStringA("###PatchCoreYoloModu: ResetDefaultParam failed.\n");
    }

    return nRet;
}

// ============================================================================
// 模型加载
// ============================================================================

bool CAlgorithmModule::ReloadPatchCore()
{
    m_inferencer.reset();

    if (m_patchCorePath.empty())
    {
        m_modelStatus = "PatchCore 未设置";
        return false;
    }

    try
    {
        std::wstring wpath = Utf8ToWString(m_patchCorePath);
        m_inferencer.reset(new Inferencer(wpath.c_str()));
        m_inferencer->InitOnnxEnv();
        m_inferencer->setThresholds(m_scoreThreshold, m_inferPixelThreshold);
        m_inferencer->setAreaThresholds(m_minArea);

        m_execProvider = m_inferencer->isUsingGpu() ? "GPU" : "CPU";
        m_modelStatus = "PatchCore 已加载 (" + m_execProvider + ")";
        return true;
    }
    catch (const std::exception& e)
    {
        m_inferencer.reset();
        m_lastError = std::string("PatchCore 加载失败: ") + e.what();
        m_modelStatus = m_lastError;
        OutputDebugStringA((m_lastError + "\n").c_str());
        return false;
    }
    catch (...)
    {
        m_inferencer.reset();
        m_lastError = "PatchCore 加载失败: 未知异常";
        m_modelStatus = m_lastError;
        return false;
    }
}

bool CAlgorithmModule::ReloadYolo()
{
    m_yolo.reset();

    if (m_yoloPath.empty())
    {
        return false;
    }

    try
    {
        std::wstring wpath = Utf8ToWString(m_yoloPath);
        m_yolo.reset(new YoloSegInferencer(wpath.c_str()));
        return true;
    }
    catch (const std::exception& e)
    {
        m_yolo.reset();
        m_lastError = std::string("YOLO 加载失败: ") + e.what();
        m_modelStatus = m_lastError;
        OutputDebugStringA((m_lastError + "\n").c_str());
        return false;
    }
    catch (...)
    {
        m_yolo.reset();
        m_lastError = "YOLO 加载失败: 未知异常";
        m_modelStatus = m_lastError;
        return false;
    }
}

void CAlgorithmModule::WarmUp()
{
    if (!m_warmUpEnable) return;

    try
    {
        cv::Mat dummy(m_tileSize, m_tileSize, CV_8UC3, cv::Scalar(0, 0, 0));
        if (m_inferencer.get()) m_inferencer->Run(dummy, false);
        if (m_yolo.get())       m_yolo->Infer(dummy);
    }
    catch (...)
    {
        // 预热失败不算致命,第一帧慢一点而已
        OutputDebugStringA("###PatchCoreYoloModu: warm-up failed, ignored.\n");
    }
}

// ============================================================================
// 参数设置:界面每改一个控件,VM 就调一次这里
// ============================================================================

int CAlgorithmModule::SetParam(IN const char* szParamName, IN const char* pData, IN int nDataLen)
{
    if (szParamName == NULL || strlen(szParamName) == 0 || pData == NULL)
    {
        return IMVS_EC_PARAM;
    }

    // ---------- 模型路径:变更时立即重新加载 ----------
    if (0 == strcmp("PatchCorePath", szParamName))
    {
        std::string newPath(pData);
        if (newPath != m_patchCorePath)
        {
            m_patchCorePath = newPath;
            if (ReloadPatchCore()) WarmUp();
        }
    }
    else if (0 == strcmp("YoloPath", szParamName))
    {
        std::string newPath(pData);
        if (newPath != m_yoloPath)
        {
            m_yoloPath = newPath;
            if (ReloadYolo()) WarmUp();
        }
    }

    // ---------- 分块参数 ----------
    else if (0 == strcmp("TileSize", szParamName))      m_tileSize      = atoi(pData);
    else if (0 == strcmp("Overlap", szParamName))       m_overlap       = atoi(pData);
    else if (0 == strcmp("MinMaskPixels", szParamName)) m_minMaskPixels = atoi(pData);

    // ---------- 后处理参数 ----------
    else if (0 == strcmp("PixelThreshold", szParamName)) m_pixelThreshold = atof(pData);
    else if (0 == strcmp("ContourWidth", szParamName))   m_contourWidth   = atoi(pData);
    else if (0 == strcmp("MinArea", szParamName))
    {
        m_minArea = atof(pData);
        // Inferencer 内部也保存了一份面积阈值,保持同步
        if (m_inferencer.get()) m_inferencer->setAreaThresholds(m_minArea);
    }

    // ---------- PatchCore 内部阈值:不用重新加载模型,热更新即可 ----------
    else if (0 == strcmp("ScoreThreshold", szParamName))
    {
        m_scoreThreshold = (float)atof(pData);
        if (m_inferencer.get()) m_inferencer->setThresholds(m_scoreThreshold, m_inferPixelThreshold);
    }
    else if (0 == strcmp("InferPixelThreshold", szParamName))
    {
        m_inferPixelThreshold = (float)atof(pData);
        if (m_inferencer.get()) m_inferencer->setThresholds(m_scoreThreshold, m_inferPixelThreshold);
    }

    // ---------- YOLO 参数 ----------
    else if (0 == strcmp("YoloConf", szParamName)) m_yoloConf = (float)atof(pData);
    else if (0 == strcmp("YoloIou", szParamName))  m_yoloIou  = (float)atof(pData);

    // ---------- 运行选项 ----------
    else if (0 == strcmp("OutputImageType", szParamName)) m_outputImageType = atoi(pData);
    else if (0 == strcmp("WarmUpEnable", szParamName))
    {
        m_warmUpEnable = (0 == _stricmp(pData, "True") || 0 == strcmp(pData, "1"));
    }

    return IMVS_EC_OK;
}

// ============================================================================
// 参数读取:界面打开时回填,以及自定义面板查状态
// ============================================================================

int CAlgorithmModule::GetParam(IN const char* szParamName, OUT char* pBuff,
                               IN int nBuffSize, OUT int* pDataLen)
{
    if (szParamName == NULL || strlen(szParamName) == 0 ||
        pBuff == NULL || nBuffSize <= 0 || pDataLen == NULL)
    {
        return IMVS_EC_PARAM;
    }

    char tmp[64] = { 0 };

    if      (0 == strcmp("PatchCorePath", szParamName)) return FillOutBuffer(m_patchCorePath, pBuff, nBuffSize, pDataLen);
    else if (0 == strcmp("YoloPath", szParamName))      return FillOutBuffer(m_yoloPath,      pBuff, nBuffSize, pDataLen);
    else if (0 == strcmp("ModelStatus", szParamName))   return FillOutBuffer(m_modelStatus,   pBuff, nBuffSize, pDataLen);
    else if (0 == strcmp("ExecProvider", szParamName))  return FillOutBuffer(m_execProvider,  pBuff, nBuffSize, pDataLen);

    else if (0 == strcmp("TileSize", szParamName))        { sprintf_s(tmp, "%d", m_tileSize); }
    else if (0 == strcmp("Overlap", szParamName))         { sprintf_s(tmp, "%d", m_overlap); }
    else if (0 == strcmp("MinMaskPixels", szParamName))   { sprintf_s(tmp, "%d", m_minMaskPixels); }
    else if (0 == strcmp("ContourWidth", szParamName))    { sprintf_s(tmp, "%d", m_contourWidth); }
    else if (0 == strcmp("OutputImageType", szParamName)) { sprintf_s(tmp, "%d", m_outputImageType); }
    else if (0 == strcmp("WarmUpEnable", szParamName))    { sprintf_s(tmp, "%s", m_warmUpEnable ? "True" : "False"); }

    else if (0 == strcmp("PixelThreshold", szParamName))      { sprintf_s(tmp, "%.4f", m_pixelThreshold); }
    else if (0 == strcmp("MinArea", szParamName))             { sprintf_s(tmp, "%.2f", m_minArea); }
    else if (0 == strcmp("ScoreThreshold", szParamName))      { sprintf_s(tmp, "%.4f", m_scoreThreshold); }
    else if (0 == strcmp("InferPixelThreshold", szParamName)) { sprintf_s(tmp, "%.4f", m_inferPixelThreshold); }
    else if (0 == strcmp("YoloConf", szParamName))            { sprintf_s(tmp, "%.4f", m_yoloConf); }
    else if (0 == strcmp("YoloIou", szParamName))             { sprintf_s(tmp, "%.4f", m_yoloIou); }

    else return IMVS_EC_PARAM;

    return FillOutBuffer(std::string(tmp), pBuff, nBuffSize, pDataLen);
}

// ============================================================================
// 图像转换
// ============================================================================

bool CAlgorithmModule::HkaImageToMat(const HKA_IMAGE& src, cv::Mat& dst)
{
    if (src.data[0] == NULL || src.width <= 0 || src.height <= 0)
    {
        return false;
    }

    // VmModule_GetInputImage 只会产出这两种格式之一(见 VmModule_iMVSFormatToAlgFormat)
    switch (src.format)
    {
    case HKA_IMG_MONO_08:
        // 灰度先包一层再转 BGR ------ 两个推理器都按 3 通道设计
        {
            cv::Mat gray(src.height, src.width, CV_8UC1, src.data[0], src.step[0]);
            cv::cvtColor(gray, dst, cv::COLOR_GRAY2BGR);
        }
        return true;

    case HKA_IMG_RGB_RGB24_C3:
        // VM 给的是 RGB 排列,OpenCV 全程按 BGR 处理,这里必须换一次通道序
        {
            cv::Mat rgb(src.height, src.width, CV_8UC3, src.data[0], src.step[0]);
            cv::cvtColor(rgb, dst, cv::COLOR_RGB2BGR);
        }
        return true;

    default:
        return false;
    }
}

static void OutImageDbg(const char* s)
{
	OutputDebugStringA(s);
	FILE* f = NULL;
	if (fopen_s(&f, "C:\\Users\\lixia\\Doubao\\chats\\2026-09-29\\new-chat\\outimage_debug.txt", "a") == 0 && f)
	{
		fputs(s, f);
		fclose(f);
	}
}

int CAlgorithmModule::OutputMat(void* hOutput, const cv::Mat& mat)
{
	if (mat.empty()) { OutImageDbg("###OutImg: mat EMPTY\n"); return IMVS_EC_PARAM; }

	//删掉了----
	return nRet;
}

// ============================================================================
// 结果统计
// ============================================================================

int CAlgorithmModule::CountDefects(const cv::Mat& predMask, double& totalArea)
{
    totalArea = 0.0;
    if (predMask.empty()) return 0;

    // TileStitcher 已经按 minArea 过滤过了,这里数的就是最终缺陷数
    std::vector<std::vector<cv::Point> > contours;
    cv::findContours(predMask.clone(), contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);

    for (size_t i = 0; i < contours.size(); ++i)
    {
        totalArea += cv::contourArea(contours[i]);
    }
    return (int)contours.size();
}

// ============================================================================
// Process:每帧调用
// ============================================================================

int CAlgorithmModule::Process(IN void* hInput, IN void* hOutput,
                              IN MVDSDK_BASE_MODU_INPUT* modu_input)
{
    int nErrCode = IMVS_EC_OK;
    m_lastError.clear();

    // 先把所有输出置成"无结果",任何一条 return 路径都不会留下上一帧的脏值
    VM_M_SetInt  (hOutput, "DefectCount", 0, 0);
    VM_M_SetFloat(hOutput, "MaxScore",    0, 0.0f);
    VM_M_SetFloat(hOutput, "TotalArea",   0, 0.0f);
    VM_M_SetInt  (hOutput, "MaskPixels",  0, 0);
    VM_M_SetInt  (hOutput, "TileCount",   0, 0);
    VM_M_SetInt  (hOutput, "TileSkipped", 0, 0);
    VM_M_SetFloat(hOutput, "YoloMs",      0, 0.0f);
    VM_M_SetFloat(hOutput, "PredictMs",   0, 0.0f);
    VM_M_SetFloat(hOutput, "PostMs",      0, 0.0f);
    VM_M_SetFloat(hOutput, "TotalMs",     0, 0.0f);
    VM_M_SetString(hOutput, "ErrorMsg",   0, "");

    const auto tAll0 = std::chrono::steady_clock::now();

    //推理部分删掉了--------------
    return nErrCode;
}

// ============================================================================
// 导出接口
// ============================================================================

PATCHCOREYOLO_API CAbstractUserModule* __stdcall CreateModule(void* hModule)
{
    assert(hModule != NULL);

    CAlgorithmModule* pUserModule = new(std::nothrow) CAlgorithmModule;
    if (pUserModule == NULL)
    {
        return NULL;
    }

    pUserModule->m_hModule = hModule;

    if (IMVS_EC_OK != pUserModule->Init())
    {
        delete pUserModule;
        return NULL;
    }

    OutputDebugStringA("###PatchCoreYoloModu: CreateModule\n");
    return pUserModule;
}

PATCHCOREYOLO_API void __stdcall DestroyModule(void* hModule, CAbstractUserModule* pUserModule)
{
    assert(hModule != NULL);
    OutputDebugStringA("###PatchCoreYoloModu: DestroyModule\n");

    if (pUserModule != NULL)
    {
        delete pUserModule;
    }
}

5 最后将所有动态库拷贝到指定目录就行

看下效果

识别结果

缺陷掩膜

实例分割掩膜

相关推荐
制造业的搬运工1 小时前
车载 PCB 打样周期与选型指南:从 IATF 16949 到 IPC-6012 的 5 个硬指标
大数据·网络·人工智能·制造·pcb工艺
55873 生态系统1 小时前
55873 正和博弈经济模型:重构数字时代商业价值体系
大数据·人工智能·重构·全域文明操作系统·55873 操作系统·55873全域文明生态体系
lengxuenong1 小时前
枚举例题分析
c++·算法·青少年编程
法狗狗技术团队1 小时前
2026年标书审查工具测评:AI标书检查软件怎么选?
人工智能·招投标·投标·标书检查·标书审查·标书制作·投标全流程
“AI国潮设计-小江”1 小时前
【SDXL实战】用AI生成“财神爷蛋糕×英歌舞人物”潮汕国潮甜品IP,附Prompt与批量生成思路
开发语言·人工智能·python·aigc
Bode_20021 小时前
企业数智孪生构建方法
人工智能·智能制造
jqpwxt1 小时前
启点创新科技景区私有化票务管理系统:智慧景区数字化建设核心服务商,以本地部署筑牢景区数字化安全与稳定底座
大数据·人工智能·科技·云计算·旅游
skywalk81631 小时前
Deepseek harness的4种模式 配置文件内容
linux·人工智能·ubuntu·deepseek·harness
货拉拉技术1 小时前
构建稳定的 AI Agent:Harness 工程的核心机制与实践思考
人工智能·后端·数据分析