鱼C论坛

 找回密码
 立即注册
查看: 104|回复: 3

C++图片裁切问题

[复制链接]
发表于 2024-11-8 20:29:41 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
最近遇到特大图片不能预览问题,所以我想直接以裁切局部区域来预览。但是试了很久总会出现问题,请帮忙写一个代码。

用C++里的Opencv加载一张图片,将图片缩放后绘制到picture控件,然后在缩放的图片上用鼠标绘制一个矩形区域,然后在缩放前的原始图片上相同位置裁切选择的这一块区域的图片再绘制到另一个picture控件里显示出来,请问这种怎么做?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2024-11-8 20:30:01 | 显示全部楼层
为了实现你描述的功能,需要以下步骤:

1. **加载和缩放图片**:读取图片并进行缩放,以便在一个较小的控件中预览。
2. **鼠标事件处理**:检测鼠标点击和拖动事件,以便在缩放后的图片上绘制矩形。
3. **映射坐标**:将缩放后图片的矩形坐标映射回原始图片上的坐标。
4. **裁切原始图片**:根据映射的坐标从原始图片中剪切出选定的区域。
5. **显示裁切结果**:将裁切的图片显示到另一个控件。

下面是一个简化的代码示例,演示了如何使用 OpenCV 加载、缩放、处理鼠标事件、以及图片裁切和显示:
#include <opencv2/opencv.hpp>
#include <iostream>

using namespace cv;
using namespace std;

// 记录鼠标事件的起始和结束点
Point start, end;
bool drawing = false;

// 鼠标事件回调函数
void mouseCallback(int event, int x, int y, int, void*)
{
    if (event == EVENT_LBUTTONDOWN)
    {
        drawing = true;
        start = Point(x, y);
        end = Point(x, y);
    }
    else if (event == EVENT_MOUSEMOVE && drawing)
    {
        end = Point(x, y);
    }
    else if (event == EVENT_LBUTTONUP)
    {
        drawing = false;
        end = Point(x, y);
    }
}

int main(int argc, char** argv)
{
    // 加载原始图像
    Mat originalImage = imread("path_to_your_image.jpg");
    if (originalImage.empty())
    {
        cout << "Could not open or find the image" << endl;
        return -1;
    }

    // 缩放图像
    Mat resizedImage;
    double scaleFactor = 0.5;
    resize(originalImage, resizedImage, Size(), scaleFactor, scaleFactor);

    // 创建窗口和设置鼠标回调
    namedWindow("Picture", WINDOW_AUTOSIZE);
    setMouseCallback("Picture", mouseCallback);

    while (true)
    {
        // 显示缩放图像
        Mat tempImage = resizedImage.clone();
        if (drawing)
        {
            rectangle(tempImage, start, end, Scalar(0, 255, 0), 2);
        }
        imshow("Picture", tempImage);

        // 等待键盘输入
        char c = (char)waitKey(10);
        if (c == 27) // 按下 'ESC' 键退出
            break;
        else if (c == 'c' && !drawing) // 按下 'c' 键裁切
        {
            // 将缩放后的坐标映射回原始图像
            Rect selectedRect(Point(start.x / scaleFactor, start.y / scaleFactor),
                              Point(end.x / scaleFactor, end.y / scaleFactor));
            Mat croppedImage = originalImage(selectedRect);

            // 显示裁切后的图像
            imshow("Cropped Image", croppedImage);
        }
    }

    return 0;
}

### 要点说明:
- `mouseCallback`函数处理鼠标事件,记录矩形选择区域。
- 键盘输入`c`用于进行裁切。
- `Rect`对象用于定义感兴趣区域,座标映射通过缩放因子进行调整。
- 确保图像路径正确,并根据需要调整缩放因子和窗口标题。

这段代码基本实现了上述功能,你可以根据实际应用需求进行进一步调整和优化。例如,可能还需要处理边界检查以及不同的显示控件。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2024-11-9 13:53:04 | 显示全部楼层
FishC 发表于 2024-11-8 20:30
为了实现你描述的功能,需要以下步骤:

1. **加载和缩放图片**:读取图片并进行缩放,以便在一个较小的 ...

setMouseCallback这个回调函数只能imshow显示的窗口,我是将图像绘制到主窗口的Picture control控件里的rect区域,这应该怎么处理?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-11-9 13:53:16 | 显示全部楼层
cxnet 发表于 2024-11-09 13:53
setMouseCallback这个回调函数只能imshow显示的窗口, ...


如果你是将图像绘制到GUI应用程序的控件中,而不是使用OpenCV的`imshow`窗口,则需要在GUI框架中处理鼠标事件。这通常需要使用特定的GUI库来实现。以下是如何在Windows应用程序中使用MFC(Microsoft Foundation Classes)来实现这一功能的思路:

1. **在Picture控件中显示缩放后的图像**:
   - 你可以使用OpenCV读取图像并缩放,然后将其转换为MFC支持的格式(如HBITMAP),然后将这张图像显示在控件上。

2. **处理鼠标事件**:
   - 在MFC中,你可以覆盖控件的鼠标事件处理函数。例如,覆盖`OnLButtonDown`、`OnMouseMove`和`OnLButtonUp`函数来处理鼠标点击和拖动。

3. **绘制选择矩形**:
   - 在鼠标移动时,记录鼠标位置,更新并重绘控件以显示选择的矩形。

4. **将矩形映射到原始图像并裁剪**:
   - 根据缩放比及控件显示区域,将选择的矩形映射回原始图像上,然后使用OpenCV裁切原始图像相应区域。

5. **在另一个控件中显示裁切结果**:
   - 将裁切的图像转换为MFC支持的格式,并显示在另一个Picture控件上。

下面是一个思路示例,并不是完整代码:
// Example MFC Picture Control message map to handle mouse events
BEGIN_MESSAGE_MAP(CYourPictureCtrlClass, CStatic)
    ON_WM_LBUTTONDOWN()
    ON_WM_MOUSEMOVE()
    ON_WM_LBUTTONUP()
END_MESSAGE_MAP()

// 在Picture控件类中添加对鼠标事件的处理
void CYourPictureCtrlClass::OnLButtonDown(UINT nFlags, CPoint point)
{
    // 记录起始点
    startPoint = point;
    isDrawing = true;
    CStatic::OnLButtonDown(nFlags, point);
}

void CYourPictureCtrlClass::OnMouseMove(UINT nFlags, CPoint point)
{
    if (isDrawing)
    {
        // 更新结束点并重绘控件
        endPoint = point;
        Invalidate(); // 触发WM_PAINT重绘
    }
    CStatic::OnMouseMove(nFlags, point);
}

void CYourPictureCtrlClass::OnLButtonUp(UINT nFlags, CPoint point)
{
    if (isDrawing)
    {
        endPoint = point;
        isDrawing = false;

        // 在此处可以进行裁剪逻辑:
        // 1. 确定缩放比
        // 2. 映射到原始图像坐标
        // 3. 使用OpenCV裁剪原始图像
        // 4. 显示到另一个控件
    }
    CStatic::OnLButtonUp(nFlags, point);
}

// 绘制功能,例如在控件上绘制选择的矩形框
void CYourPictureCtrlClass::OnPaint()
{
    CPaintDC dc(this); // 用于绘制的设备上下文
    // 在此处绘制缩放后的图像和选择矩形
}

**注意**:具体的实现细节会根据你的MFC工程结构和需求(例如,如何加载和显示图片,如何转换OpenCV图片到MFC格式)有所不同。主要思路是利用Windows的消息机制处理鼠标输入,结合OpenCV进行图像处理。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-11-21 18:59

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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