mrDarker
2025-08-16 df45966c52bac2eb465cf05c1d6328bf0d00c5ac
1. 补提交添加保存图像的类
已添加2个文件
239 ■■■■■ 文件已修改
EdgeInspector_App/Thread/Thread_SaveFullImg.cpp 194 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
EdgeInspector_App/Thread/Thread_SaveFullImg.h 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
EdgeInspector_App/Thread/Thread_SaveFullImg.cpp
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,194 @@
#include "stdafx.h"
#include "Thread_SaveFullImg.h"
static void TightCopy(std::vector<BYTE>& vDst, const BYTE* pSrc, int nWidth, int nHeight, int nStride, int nBpp)
{
    const int nTight = nWidth * nBpp;
    vDst.resize(size_t(nTight) * nHeight);
    if (vDst.empty() || nHeight < 1 || nWidth < 1 || nBpp < 1) {
        g_pLog->DisplayMessage(_T("TightCopy: Invalid parameters, nWidth=%d, nHeight=%d, nBpp=%d"), nWidth, nHeight, nBpp);
        return;
    }
    // å¦‚æžœ nStride ç­‰äºŽ nTight,说明源数据是紧密行存储
    if (nStride == nTight) {
        memcpy(vDst.data(), pSrc, vDst.size());
        return;
    }
    // å¦‚æžœ nStride å°äºŽ nTight,说明源数据不是紧密行存储
    if (nStride < nTight) {
        g_pLog->DisplayMessage(_T("TightCopy: Invalid nStride %d < nTight %d"), nStride, nTight);
        return;
    }
    // å¦‚æžœ nStride å¤§äºŽ nTight,逐行复制
    for (int y = 0; y < nHeight; ++y) {
        memcpy(vDst.data() + size_t(y) * nTight, pSrc + size_t(y) * nStride, nTight);
    }
}
CThread_SaveFullImg::CThread_SaveFullImg()
{
    m_bStop = false;
}
CThread_SaveFullImg::~CThread_SaveFullImg()
{
    StopThread();
}
void CThread_SaveFullImg::CreateThread()
{
    if (m_Thread.joinable()) {
        return;
    }
    m_bStop = false;
    m_Thread = std::thread([this] { ThreadProc(); });
}
void CThread_SaveFullImg::StopThread()
{
    {
        std::lock_guard<std::mutex> oLock(m_Mtx);
        m_bStop = true;
    }
    m_Cv.notify_all();
    if (m_Thread.joinable()) {
        m_Thread.join();
    }
}
void CThread_SaveFullImg::Enqueue(SaveImgJob&& oJob)
{
    {
        std::lock_guard<std::mutex> oLock(m_Mtx);
        m_Q.push(std::move(oJob));
    }
    m_Cv.notify_one();
}
size_t CThread_SaveFullImg::GetPendingCount() const
{
    std::lock_guard<std::mutex> oLock(m_Mtx);
    return m_Q.size();
}
void CThread_SaveFullImg::ThreadProc()
{
    while (true) {
        SaveImgJob oJob; {
            std::unique_lock<std::mutex> oLock(m_Mtx);
            m_Cv.wait(oLock, [this] {
                return m_bStop || !m_Q.empty();
            });
            if (m_bStop && m_Q.empty()) {
                break;
            }
            oJob = std::move(m_Q.front());
            m_Q.pop();
        }
        try {
            SaveFullImageModern(oJob);
        }
        catch (...) {
            g_pLog->DisplayMessage(_T("Async save failed: %s"), oJob.strPath.c_str());
        }
    }
}
BOOL CThread_SaveFullImg::SaveFullImageModern(const SaveImgJob& job)
{
    int iSide = job.nDimension;
    if (iSide < 0 || iSide > MAX_DIMENSION_COUNT - 1) {
        g_pLog->DisplayMessage(_T("Save Full Image Fail(%S, %d), invalid side index"), job.strPath.c_str(), job.nDimension);
        return FALSE;
    }
    if (job.vData.empty() || job.nHeight < 100 || job.nWidth < 100 || job.nBpp < 0) {
        g_pLog->DisplayMessage(_T("Save Full Image Fail(%S, %s, %d, %d)"), job.strPath.c_str(), PANEL_SIDE[iSide], job.nWidth, job.nHeight);
        return FALSE;
    }
    if (job.nStride < job.nWidth * job.nBpp) {
        g_pLog->DisplayMessage(_T("Save Full Image Fail(%S), stride(%d) < width*bpp(%d)"), job.strPath.c_str(), job.nStride, job.nWidth * job.nBpp);
        return FALSE;
    }
    int nQuality = job.nQuality;
    if (nQuality < 0) {
        nQuality = 0;
    }
    if (nQuality > 100) {
        nQuality = 100;
    }
    double dTmp = 70 / 100.0;
    double dRatio = 1.0 - dTmp;
    dRatio = dRatio - 0.01 < 0.0 ? 1.0 : dRatio;
    g_pLog->DisplayMessage(_T("Save Full Image Start(%S, %s, %d, %d, %d)"), job.strPath.c_str(), PANEL_SIDE[job.nDimension], job.nStartY, job.nHeight, nQuality);
    int nStartY = job.nStartY;
    if (nStartY < 0) {
        nStartY = 0;
    }
    if (nStartY > job.nHeight - 1) {
        nStartY = job.nHeight - 1;
    }
    int cvType;
    switch (job.nBpp)
    {
    case 1: cvType = CV_8UC1; break;
    case 3: cvType = CV_8UC3; break;
    default:
        g_pLog->DisplayMessage(_T("Save Full Image Fail(%S), unsupported nBpp=%d"), job.strPath.c_str(), job.nBpp);
        return FALSE;
    }
    const BYTE* pBase = job.vData.data() + size_t(nStartY) * size_t(job.nStride);
    const int nHAvail = job.nHeight - nStartY;
    if (nHAvail < 100) {
        g_pLog->DisplayMessage(_T("Save Full Image Skip(%S, %s), nHAvail=%d too small"), job.strPath.c_str(), PANEL_SIDE[iSide], nHAvail);
        return FALSE;
    }
    // åŽŸå§‹å›¾åƒæ•°æ®è½¬ cv::Mat
    cv::Mat origin(nHAvail, job.nWidth, cvType, (void*)pBase, size_t(job.nStride));
    // ç¼©æ”¾å›¾åƒ
    const int nOutW = std::max(1, static_cast<int>(origin.cols * dRatio));
    const int nOutH = std::max(1, static_cast<int>(origin.rows * dRatio));
    cv::Mat img;
    if (nOutW == origin.cols && nOutH == origin.rows) {
        img = origin;
    }
    else {
        cv::resize(origin, img, cv::Size(nOutW, nOutH), 0, 0, cv::INTER_LINEAR);
    }
    // è®¾ç½® JPEG åŽ‹ç¼©å‚æ•°
    std::vector<int> params = { cv::IMWRITE_JPEG_QUALITY, nQuality };
    try {
        if (!cv::imwrite(job.strPath, img, params)) {
            g_pLog->DisplayMessage(_T("Save Full Image Fail(%S, %s, %d), imwrite failed"), job.strPath.c_str(), PANEL_SIDE[iSide], nStartY);
            return FALSE;
        }
    }
    catch (...) {
        g_pLog->DisplayMessage(_T("Save Full Image Fail(%S, %s, %d), exception during imwrite"), job.strPath.c_str(), PANEL_SIDE[iSide], nStartY);
        return FALSE;
    }
    g_pLog->DisplayMessage(_T("Save Full Image Success(%S, %s, %d, %d, %d)"), job.strPath.c_str(), PANEL_SIDE[iSide], nStartY, job.nHeight, nQuality);
    return TRUE;
}
EdgeInspector_App/Thread/Thread_SaveFullImg.h
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,45 @@
#pragma once
#include <queue>
#include <mutex>
#include <condition_variable>
#include <thread>
#include <atomic>
#include <vector>
#include <string>
#include <Windows.h>
struct SaveImgJob
{
    std::string        strPath;
    std::vector<BYTE>  vData;
    int                nWidth = 0;
    int                nHeight = 0;
    int                nStride = 0;
    int                nBpp = 1;
    int                nStartY = 0;
    int                nDimension = 0;
    int                nQuality = 80;
};
class CThread_SaveFullImg
{
public:
    CThread_SaveFullImg();
    ~CThread_SaveFullImg();
    void CreateThread();
    void StopThread();
    void Enqueue(SaveImgJob&& oJob);
    size_t GetPendingCount() const;
private:
    void ThreadProc();
    BOOL SaveFullImageModern(const SaveImgJob& job);
private:
    mutable std::mutex              m_Mtx;
    std::condition_variable         m_Cv;
    std::queue<SaveImgJob>          m_Q;
    std::thread                     m_Thread;
    std::atomic<bool>               m_bStop;
};