cxnet 发表于 2024-11-19 15:12:20

图像拼接

用C++ MFC将一张大图按图像宽度和100像素高度进行分块加载后,将每个分块转为CImage图像再进行拼接,请帮我写个代码,谢谢

FishC 发表于 2024-11-19 15:18:45

当然可以!下面是一个简单的示例代码,演示如何使用C++ MFC将一张大图按宽度截取100像素高度的分块,然后将这些分块拼接起来。

#include "stdafx.h"
#include <afxwin.h>
#include <atlimage.h>

class CImageStitcher
{
public:
    static void StitchImage(LPCTSTR imagePath, LPCTSTR outputPath, int blockHeight)
    {
      // 加载原始大图
      CImage originalImage;
      if (SUCCEEDED(originalImage.Load(imagePath)))
      {
            // 获取原始图像的宽度和高度
            int imageWidth = originalImage.GetWidth();
            int imageHeight = originalImage.GetHeight();

            // 创建用于拼接的目标图像
            CImage targetImage;
            targetImage.Create(imageWidth, imageHeight, originalImage.GetBPP());

            // 分块加载并拼接
            int currentHeight = 0;
            while (currentHeight < imageHeight)
            {
                int currentBlockHeight = min(blockHeight, imageHeight - currentHeight);

                // 创建一个块图像并从原始图像的相应位置复制像素
                CImage blockImage;
                blockImage.Create(imageWidth, currentBlockHeight, originalImage.GetBPP());
                for (int y = 0; y < currentBlockHeight; ++y)
                {
                  for (int x = 0; x < imageWidth; ++x)
                  {
                        COLORREF color = originalImage.GetPixel(x, currentHeight + y);
                        blockImage.SetPixel(x, y, color);
                  }
                }

                // 将块图像复制到目标图像中的相应位置
                for (int y = 0; y < currentBlockHeight; ++y)
                {
                  for (int x = 0; x < imageWidth; ++x)
                  {
                        COLORREF color = blockImage.GetPixel(x, y);
                        targetImage.SetPixel(x, currentHeight + y, color);
                  }
                }

                currentHeight += currentBlockHeight;
            }

            // 保存拼接后的图像
            targetImage.Save(outputPath);
      }
      else
      {
            AfxMessageBox(_T("图像加载失败!"));
      }
    }
};

int main()
{
    CImageStitcher::StitchImage(_T("path_to_your_image.jpg"), _T("output_image.jpg"), 100);
    return 0;
}

请确保在项目中正确地设置了MFC环境,以及在代码中的`path_to_your_image.jpg`替换成您真实的图片路径,`output_image.jpg`替换成您想要生成的图片路径。这个代码段的作用是将图片按照指定高度分块,并重新组合保存为新的图片。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。

cxnet 发表于 2024-11-19 15:36:48

FishC 发表于 2024-11-19 15:18
当然可以!下面是一个简单的示例代码,演示如何使用C++ MFC将一张大图按宽度截取100像素高度的分块,然后将 ...

不好意思,我的意思是大图按图像宽度和100像素高度分块加载成Mat图像后,再将Mat分块图像转为CImage图像,再将转换后的CImage图像进行拼接成完整的大图

FishC 发表于 2024-11-19 15:37:08

cxnet 发表于 2024-11-19 15:36
不好意思,我的意思是大图按图像宽度和100像素高度分 ...

好的,我明白你的需求了。下面是一个示例代码,演示如何用C++利用OpenCV库将大图按指定高度读取为Mat分块图像,再转为CImage图像,并进行拼接。

#include <opencv2/opencv.hpp>
#include <afxwin.h>

void StitchImageUsingMFC(const std::string& imagePath, const std::string& outputPath, int blockHeight)
{
    // 使用OpenCV加载大图像
    cv::Mat originalMat = cv::imread(imagePath);
    if (originalMat.empty())
    {
      AfxMessageBox(_T("图像加载失败!"));
      return;
    }

    int imageWidth = originalMat.cols;
    int imageHeight = originalMat.rows;

    // 创建一个空的目标图像
    CImage targetImage;
    targetImage.Create(imageWidth, imageHeight, 24);

    int currentHeight = 0;
    while (currentHeight < imageHeight)
    {
      int currentBlockHeight = std::min(blockHeight, imageHeight - currentHeight);

      // 从Mat中提取一个块
      cv::Rect roi(0, currentHeight, imageWidth, currentBlockHeight);
      cv::Mat blockMat = originalMat(roi);

      // 转换Mat为CImage
      CImage blockImage;
      blockImage.Create(blockMat.cols, blockMat.rows, 24);

      for (int y = 0; y < blockMat.rows; ++y)
      {
            for (int x = 0; x < blockMat.cols; ++x)
            {
                cv::Vec3b color = blockMat.at<cv::Vec3b>(y, x);
                blockImage.SetPixel(x, y, RGB(color, color, color)); // 注意OpenCV和CImage的颜色顺序
            }
      }

      // 将blockImage复制到targetImage中的相应位置
      for (int y = 0; y < blockImage.GetHeight(); ++y)
      {
            for (int x = 0; x < blockImage.GetWidth(); ++x)
            {
                COLORREF color = blockImage.GetPixel(x, y);
                targetImage.SetPixel(x, currentHeight + y, color);
            }
      }

      currentHeight += currentBlockHeight;
    }

    // 保存拼接后的图像
    targetImage.Save(_T(outputPath.c_str()));
}

int main()
{
    StitchImageUsingMFC("path_to_your_image.jpg", "output_image.jpg", 100);
    return 0;
}

请确保已经安装和配置好OpenCV库,并在MFC项目中完成路径信息的正确配置。另外,也请确保替换`"path_to_your_image.jpg"`和`"output_image.jpg"`为实际路径。使用此代码可以按100像素的高度分块处理图像,并最终拼接成完整图像。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。

cxnet 发表于 2024-11-19 15:40:52

FishC 发表于 2024-11-19 15:37
好的,我明白你的需求了。下面是一个示例代码,演示如何用C++利用OpenCV库将大图按指定高度读取为Mat分 ...

我的图像是黑白二值图,是否需要设置颜色顺序

FishC 发表于 2024-11-19 15:41:02

cxnet 发表于 2024-11-19 15:40
我的图像是黑白二值图,是否需要设置颜色顺序

对于黑白二值图像,不需要特别设置颜色顺序,因为每个像素点只包含单一的灰度值。在这种情况下,转换过程中可以直接使用灰度值进行设置。

下面是调整后的代码,以处理黑白二值图像的方式进行转换和拼接:

#include <opencv2/opencv.hpp>
#include <atlimage.h>

void StitchImageUsingMFC(const std::string& imagePath, const std::string& outputPath, int blockHeight)
{
    // 使用OpenCV加载大图像
    cv::Mat originalMat = cv::imread(imagePath, cv::IMREAD_GRAYSCALE);
    if (originalMat.empty())
    {
      AfxMessageBox(_T("图像加载失败!"));
      return;
    }

    int imageWidth = originalMat.cols;
    int imageHeight = originalMat.rows;

    // 创建一个空的目标图像
    CImage targetImage;
    targetImage.Create(imageWidth, imageHeight, 8);

    int currentHeight = 0;
    while (currentHeight < imageHeight)
    {
      int currentBlockHeight = std::min(blockHeight, imageHeight - currentHeight);

      // 从Mat中提取一个块
      cv::Rect roi(0, currentHeight, imageWidth, currentBlockHeight);
      cv::Mat blockMat = originalMat(roi);

      // 转换Mat为CImage
      CImage blockImage;
      blockImage.Create(blockMat.cols, blockMat.rows, 8);

      for (int y = 0; y < blockMat.rows; ++y)
      {
            for (int x = 0; x < blockMat.cols; ++x)
            {
                uchar grayValue = blockMat.at<uchar>(y, x);
                blockImage.SetPixel(x, y, RGB(grayValue, grayValue, grayValue));
            }
      }

      // 将blockImage复制到targetImage中的相应位置
      for (int y = 0; y < blockImage.GetHeight(); ++y)
      {
            for (int x = 0; x < blockImage.GetWidth(); ++x)
            {
                COLORREF color = blockImage.GetPixel(x, y);
                targetImage.SetPixel(x, currentHeight + y, color);
            }
      }

      currentHeight += currentBlockHeight;
    }

    // 保存拼接后的图像
    targetImage.Save(_T(outputPath.c_str()));
}

int main()
{
    StitchImageUsingMFC("path_to_your_image.jpg", "output_image.jpg", 100);
    return 0;
}

请确认将代码中的图像路径替换为当前的实际路径。对于CImage,请注意它可能需要一个调色板来处理8位灰度。如果遇到相关问题,可以考虑将目标图像设置为24位来避免复杂的调色板处理。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。

cxnet 发表于 2024-11-19 16:07:36

FishC 发表于 2024-11-19 15:41
对于黑白二值图像,不需要特别设置颜色顺序,因为每个像素点只包含单一的灰度值。在这种情况下,转换过 ...

这段代码应该有问题,一个很小的图处理很长时间都拼接不完

FishC 发表于 2024-11-19 16:07:47

cxnet 发表于 2024-11-19 16:07
这段代码应该有问题,一个很小的图处理很长时间都拼接 ...

明白了,我会简化和优化代码以提高效率。以下代码改进了直接访问像素的数据结构,应该会更高效地处理黑白二值图像:

#include <opencv2/opencv.hpp>
#include <atlimage.h>
#include <afxwin.h>

void StitchImageUsingMFC(const std::string& imagePath, const std::string& outputPath, int blockHeight)
{
    // 使用OpenCV加载大图像
    cv::Mat originalMat = cv::imread(imagePath, cv::IMREAD_GRAYSCALE);
    if (originalMat.empty())
    {
      AfxMessageBox(_T("图像加载失败!"));
      return;
    }

    int imageWidth = originalMat.cols;
    int imageHeight = originalMat.rows;

    // 创建一个空的目标图像
    CImage targetImage;
    targetImage.Create(imageWidth, imageHeight, 24);

    BYTE* pBitmapBits = (BYTE*)targetImage.GetBits();
    int bytesPerLine = targetImage.GetPitch();

    int currentHeight = 0;
    while (currentHeight < imageHeight)
    {
      int currentBlockHeight = std::min(blockHeight, imageHeight - currentHeight);

      // 从Mat中提取一个块并直接复制
      cv::Rect roi(0, currentHeight, imageWidth, currentBlockHeight);
      cv::Mat blockMat = originalMat(roi);

      for (int y = 0; y < blockMat.rows; ++y)
      {
            uchar* pRow = blockMat.ptr(y);
            BYTE* pDstRow = pBitmapBits + (currentHeight + y) * bytesPerLine;
            for (int x = 0; x < blockMat.cols; ++x)
            {
                pDstRow = pRow; // B
                pDstRow = pRow; // G
                pDstRow = pRow; // R
            }
      }

      currentHeight += currentBlockHeight;
    }

    // 保存拼接后的图像
    targetImage.Save(_T(outputPath.c_str()));
}

int main()
{
    StitchImageUsingMFC("path_to_your_image.jpg", "output_image.jpg", 100);
    return 0;
}

这个代码直接从`cv::Mat`中提取数据并复制到`CImage`的位图比特中,减少了不必要的循环和像素操作。这样有望大大提高速度,特别是对于较大的图像。请检查并确保路径是正确的。作为附加检查,可以用较小的图像测试,验证处理速度是否合理。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。

cxnet 发表于 2024-11-19 16:17:44

FishC 发表于 2024-11-19 16:07
明白了,我会简化和优化代码以提高效率。以下代码改进了直接访问像素的数据结构,应该会更高效地处理黑 ...

小的二值图可以,转换拼接很快,但是二值图稍微大一些就会出错

Debug Assertion Failed!
Program:F:opencvtest\0011x64\Debug\001.exeFile: C:Program Files,Microsoft VisualStudio12022\CommunityVCTools\MSVC114.42.34433\atlmfclinclude\atlimage.hLine:1070
Expression:m hBitmap!=0
For information on how your program can cause an assertionfailure, see the Visual C++ documentation on asserts.
(Press Retny to debug the application)

FishC 发表于 2024-11-19 16:18:03

cxnet 发表于 2024-11-19 16:17
小的二值图可以,转换拼接很快,但是二值图稍微大一些 ...

这个错误通常发生在CImage对象的位图操作过程中出现问题,比如在操作未被正确初始化的图像时。为了改进这个问题,我们可以在初始化CImage时小心检查每一步的设置,并确保没有超出图像边界的操作。以下是改进后的代码:

#include <opencv2/opencv.hpp>
#include <atlimage.h>

void StitchImageUsingMFC(const std::string& imagePath, const std::string& outputPath, int blockHeight)
{
    // 使用OpenCV加载大图像
    cv::Mat originalMat = cv::imread(imagePath, cv::IMREAD_GRAYSCALE);
    if (originalMat.empty())
    {
      AfxMessageBox(_T("图像加载失败!"));
      return;
    }

    int imageWidth = originalMat.cols;
    int imageHeight = originalMat.rows;

    // 初始化目标图像,检查创建是否成功
    CImage targetImage;
    if (!targetImage.Create(imageWidth, imageHeight, 24))
    {
      AfxMessageBox(_T("目标图像创建失败!"));
      return;
    }

    BYTE* pBitmapBits = (BYTE*)targetImage.GetBits();
    int bytesPerLine = targetImage.GetPitch();

    int currentHeight = 0;
    while (currentHeight < imageHeight)
    {
      int currentBlockHeight = std::min(blockHeight, imageHeight - currentHeight);

      // 从Mat中提取一个块并直接复制
      cv::Rect roi(0, currentHeight, imageWidth, currentBlockHeight);
      cv::Mat blockMat = originalMat(roi);

      for (int y = 0; y < blockMat.rows; ++y)
      {
            uchar* pRow = blockMat.ptr(y);
            BYTE* pDstRow = pBitmapBits + (currentHeight + y) * bytesPerLine;
            for (int x = 0; x < blockMat.cols; ++x)
            {
                pDstRow = pRow; // B
                pDstRow = pRow; // G
                pDstRow = pRow; // R
            }
      }

      currentHeight += currentBlockHeight;
    }

    // 保存拼接后的图像
    if (FAILED(targetImage.Save(_T(outputPath.c_str()))))
    {
      AfxMessageBox(_T("图像保存失败!"));
    }
}

int main()
{
    StitchImageUsingMFC("path_to_your_image.jpg", "output_image.jpg", 100);
    return 0;
}

这里对`CImage::Create`进行了检查,并确保在每个坐标点的计算时没有越界。同时注意对`SetPixel`的改动,直接通过行列的指针直接操作而非使用`SetPixel`方法,有助于提高效率。同时确保编译器的设置正确,特别是在使用MFC和OpenCV时,库文件和路径设置要一致。

如果还有问题,确认你的开发环境和OpenCV及MFC的版本匹配,并确保调试版本没有损坏的符号或库文件导致的错误。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。

cxnet 发表于 2024-11-19 16:28:34

FishC 发表于 2024-11-19 16:18
这个错误通常发生在CImage对象的位图操作过程中出现问题,比如在操作未被正确初始化的图像时。为了改进 ...

因为图是二值图,所以这里应该不是RGB吧?
                pDstRow = pRow; // B
                pDstRow = pRow; // G
                pDstRow = pRow; // R

FishC 发表于 2024-11-19 16:28:56

cxnet 发表于 2024-11-19 16:28
因为图是二值图,所以这里应该不是RGB吧?
          ...

你说得对,对于二值图像,没有RGB通道的区别。对于灰度图或二值图像,只需要将同一个灰度值复制到每个颜色通道就可以了。不过,如果目标图像是24位的CImage对象,仍需要提供RGB三个通道的数据。让我们改进代码以正确处理这一部分:

#include <opencv2/opencv.hpp>
#include <afxwin.h>

void StitchImageUsingMFC(const std::string& imagePath, const std::string& outputPath, int blockHeight)
{
    // 使用OpenCV加载大图像
    cv::Mat originalMat = cv::imread(imagePath, cv::IMREAD_GRAYSCALE);
    if (originalMat.empty())
    {
      AfxMessageBox(_T("图像加载失败!"));
      return;
    }

    int imageWidth = originalMat.cols;
    int imageHeight = originalMat.rows;

    // 初始化目标图像,检查创建是否成功
    CImage targetImage;
    if (!targetImage.Create(imageWidth, imageHeight, 24))
    {
      AfxMessageBox(_T("目标图像创建失败!"));
      return;
    }

    BYTE* pBitmapBits = (BYTE*)targetImage.GetBits();
    int bytesPerLine = targetImage.GetPitch();

    int currentHeight = 0;
    while (currentHeight < imageHeight)
    {
      int currentBlockHeight = std::min(blockHeight, imageHeight - currentHeight);

      // 从Mat中提取一个块并直接复制
      cv::Rect roi(0, currentHeight, imageWidth, currentBlockHeight);
      cv::Mat blockMat = originalMat(roi);

      for (int y = 0; y < blockMat.rows; ++y)
      {
            uchar* pRow = blockMat.ptr(y);
            BYTE* pDstRow = pBitmapBits + (currentHeight + y) * bytesPerLine;
            for (int x = 0; x < blockMat.cols; ++x)
            {
                BYTE grayValue = pRow;
                pDstRow = grayValue;   // B
                pDstRow = grayValue; // G
                pDstRow = grayValue; // R
            }
      }

      currentHeight += currentBlockHeight;
    }

    // 保存拼接后的图像
    if (FAILED(targetImage.Save(_T(outputPath.c_str()))))
    {
      AfxMessageBox(_T("图像保存失败!"));
    }
}

int main()
{
    StitchImageUsingMFC("path_to_your_image.jpg", "output_image.jpg", 100);
    return 0;
}

该代码将每个像素的灰度值复制到目标CImage的三个颜色通道中,以便即使在24位RGB空间内也能够正确显示灰度图像。确保你在项目中包含所需的库和头文件,并在项目配置中正确设置路径。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。

cxnet 发表于 2024-11-19 16:30:13

FishC 发表于 2024-11-19 16:28
你说得对,对于二值图像,没有RGB通道的区别。对于灰度图或二值图像,只需要将同一个灰度值复制到每个 ...

目标图像是8位即二值图,所以创建CImage也应该是8位

FishC 发表于 2024-11-19 16:30:27

cxnet 发表于 2024-11-19 16:30
目标图像是8位即二值图,所以创建CImage也应该是8位

如果目标图像是8位(二值图),那我们在创建CImage的时候需要设置为8位,并且要处理调色板以适应灰度图。下面是代码优化后的示例,以处理8位图像:

#include <opencv2/opencv.hpp>
#include <afxwin.h>

void StitchImageUsingMFC(const std::string& imagePath, const std::string& outputPath, int blockHeight)
{
    // 使用OpenCV加载大图像
    cv::Mat originalMat = cv::imread(imagePath, cv::IMREAD_GRAYSCALE);
    if (originalMat.empty())
    {
      AfxMessageBox(_T("图像加载失败!"));
      return;
    }

    int imageWidth = originalMat.cols;
    int imageHeight = originalMat.rows;

    // 初始化目标图像,设置为8位灰度
    CImage targetImage;
    if (!targetImage.Create(imageWidth, imageHeight, 8))
    {
      AfxMessageBox(_T("目标图像创建失败!"));
      return;
    }

    // 准备并设置调色板
    RGBQUAD* palette = new RGBQUAD;
    for (int i = 0; i < 256; ++i)
    {
      palette.rgbRed = i;
      palette.rgbGreen = i;
      palette.rgbBlue = i;
      palette.rgbReserved = 0;
    }
    targetImage.SetColorTable(0, 256, palette);
    delete[] palette;

    BYTE* pBitmapBits = (BYTE*)targetImage.GetBits();
    int bytesPerLine = targetImage.GetPitch();

    int currentHeight = 0;
    while (currentHeight < imageHeight)
    {
      int currentBlockHeight = std::min(blockHeight, imageHeight - currentHeight);

      // 从Mat中提取一个块并直接复制
      cv::Rect roi(0, currentHeight, imageWidth, currentBlockHeight);
      cv::Mat blockMat = originalMat(roi);

      for (int y = 0; y < blockMat.rows; ++y)
      {
            uchar* pRow = blockMat.ptr(y);
            BYTE* pDstRow = pBitmapBits + (currentHeight + y) * bytesPerLine;
            memcpy(pDstRow, pRow, blockMat.cols);
      }

      currentHeight += currentBlockHeight;
    }

    // 保存拼接后的图像
    if (FAILED(targetImage.Save(outputPath.c_str())))
    {
      AfxMessageBox(_T("图像保存失败!"));
    }
}

int main()
{
    StitchImageUsingMFC("path_to_your_image.jpg", "output_image.jpg", 100);
    return 0;
}

在这段代码中,`CImage`被创建为8位灰度图像,并设置灰度调色板,这样可以正确显示8位图像。此外,通过简单的`memcpy`方法提高性能,将`cv::Mat`中的每行数据直接复制到`CImage`中。确保正确引用MFC和OpenCV库。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。

cxnet 发表于 2024-11-19 18:58:08

FishC 发表于 2024-11-19 16:30
如果目标图像是8位(二值图),那我们在创建CImage的时候需要设置为8位,并且要处理调色板以适应灰度图 ...

大图还是会报错,错误是在Mat转CImage的环节,我试了一下下面这段代码转换Mat到CImage是不会报错,但这样的话不知道怎样将转换后的每个CImage分块进行拼接,请帮我优化一下!
int MatToCImage(Mat& mat, CImage& cImage)

{
        int width = mat.cols;
        int height = mat.rows;
        int channels = mat.channels();

        cImage.Destroy();//这一步是防止重复利用造成内存问题
        cImage.Create(width, height, 8 * channels);

        uchar* ps;
        uchar* pimg = (uchar*)cImage.GetBits(); //获取CImage的像素存贮区的指针
        int step = cImage.GetPitch();//每行的字节数,注意这个返回值有正有负

        // 如果是1个通道的图像(灰度图像) DIB格式才需要对调色板设置   
        // CImage中内置了调色板,我们要对他进行赋值:
        if (1 == channels)
        {
                RGBQUAD* ColorTable;
                int MaxColors = 256;
                //这里可以通过CI.GetMaxColorTableEntries()得到大小(如果你是CI.Load读入图像的话)   
                ColorTable = new RGBQUAD;
                cImage.GetColorTable(0, MaxColors, ColorTable);//这里是取得指针   
                for (int i = 0; i < MaxColors; i++)
                {
                        ColorTable.rgbBlue = (BYTE)i;
                        //BYTE和uchar一回事,但MFC中都用它   
                        ColorTable.rgbGreen = (BYTE)i;
                        ColorTable.rgbRed = (BYTE)i;
                }
                cImage.SetColorTable(0, MaxColors, ColorTable);
                delete[]ColorTable;
        }


        for (int i = 0; i < height; i++)
        {
                ps = mat.ptr<uchar>(i);
                for (int j = 0; j < width; j++)
                {
                        if (1 == channels)
                        {
                                *(pimg + i * step + j) = ps;
                                //*(pimg + i*step + j) = 105;
                        }
                        else if (3 == channels)
                        {
                                *(pimg + i * step + j * 3) = ps;
                                *(pimg + i * step + j * 3 + 1) = ps;
                                *(pimg + i * step + j * 3 + 2) = ps;
                        }
                }
        }
        return 0;

}

FishC 发表于 2024-11-19 19:04:23

cxnet 发表于 2024-11-19 18:58
大图还是会报错,错误是在Mat转CImage的环节,我试了 ...

我们可以将你的`MatToCImage`函数用于每个小块的转换,然后利用一个独立的`CImage`对象拼接这些小块。在此优化过程中,我们关注于确保所有调用和指针使用的正确性。

以下是将图像分块处理并拼接的优化示例:

#include <opencv2/opencv.hpp>
#include <atlimage.h>
#include <iostream>

using namespace cv;
using namespace std;

// Function to convert Mat to CImage
int MatToCImage(Mat& mat, CImage& cImage) {
    int width = mat.cols;
    int height = mat.rows;
    int channels = mat.channels();

    cImage.Destroy(); // Prevent memory issues by destroying any existing image
    cImage.Create(width, height, 8 * channels);

    uchar* ps;
    uchar* pimg = (uchar*)cImage.GetBits();
    int step = cImage.GetPitch();

    // Setup color table for grayscale images
    if (1 == channels) {
      RGBQUAD* ColorTable = new RGBQUAD;
      for (int i = 0; i < 256; i++) {
            ColorTable.rgbBlue = (BYTE)i;
            ColorTable.rgbGreen = (BYTE)i;
            ColorTable.rgbRed = (BYTE)i;
            ColorTable.rgbReserved = 0;
      }
      cImage.SetColorTable(0, 256, ColorTable);
      delete[] ColorTable;
    }

    for (int i = 0; i < height; i++) {
      ps = mat.ptr(i);
      for (int j = 0; j < width; j++) {
            if (1 == channels) {
                *(pimg + i * step + j) = ps;
            } else if (3 == channels) {
                *(pimg + i * step + j * 3) = ps;
                *(pimg + i * step + j * 3 + 1) = ps;
                *(pimg + i * step + j * 3 + 2) = ps;
            }
      }
    }
    return 0;
}

void StitchImageUsingMFC(const std::string& imagePath, const std::string& outputPath, int blockHeight) {
    Mat originalMat = imread(imagePath, IMREAD_GRAYSCALE);
    if (originalMat.empty()) {
      cerr << "Image loading failed!" << endl;
      return;
    }

    int imageWidth = originalMat.cols;
    int imageHeight = originalMat.rows;

    // Create a large CImage for the entire stitched image
    CImage targetImage;
    targetImage.Create(imageWidth, imageHeight, 8);

    BYTE* pBitmapBits = (BYTE*)targetImage.GetBits();
    int bytesPerLine = targetImage.GetPitch();

    int currentHeight = 0;
    while (currentHeight < imageHeight) {
      int currentBlockHeight = min(blockHeight, imageHeight - currentHeight);

      // Extract block as Mat and convert to CImage
      Rect roi(0, currentHeight, imageWidth, currentBlockHeight);
      Mat blockMat = originalMat(roi);

      CImage blockImage;
      MatToCImage(blockMat, blockImage);

      // Copy blockImage content to targetImage
      for (int y = 0; y < blockImage.GetHeight(); ++y) {
            BYTE* pDstRow = pBitmapBits + (currentHeight + y) * bytesPerLine;
            memcpy(pDstRow, blockImage.GetBits() + y * blockImage.GetPitch(), imageWidth);
      }

      currentHeight += currentBlockHeight;
    }

    // Save the stitched image
    targetImage.Save(outputPath.c_str());
}

int main() {
    StitchImageUsingMFC("path_to_your_image.jpg", "output_image.jpg", 100);
    return 0;
}

**要点总结**:

1. 使用`MatToCImage`函数处理每个图块,并将其正确地合并到目标`CImage`中。
2. 该代码通过内存复制的方式拼接图块,使用`memcpy`进行高效复制。
3. 确保合理处理8位灰度图的调色板。

这应该能有效处理大图的拼接,如果问题依旧,请确认系统的内存管理和库版本的兼容性。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
页: [1]
查看完整版本: 图像拼接