• 一步步实现看图工具(二)


    1. 控件在对话框中的适配。

    2. 图像和显示控件的适配。

    3. 以鼠标点为中心, 滚轮缩放图片(类似于手机图库)

    4. 鼠标拖动图片。(类似于手机图库)

    5。双击100%显示图片, 再次双击显示全图(类似于手机图库)

    6. 图像任意角度旋转。



    1. 控件在对话框中的适配。

       可以先参考我这篇文章: 

       http://blog.csdn.net/fallingstar08/article/details/5182830

         现在的控件不多我就这么写了

    void CEasyImageDlg::OnSize(UINT, int w, int h)
    {
    	if(m_player.GetSafeHwnd())
    	{
    		Move(&m_player, 0, 0, w, h, 0, 0, 800, 1000);
    		Move(&xyPos, 0, 0, w, h, 840,  130,100, 30);
    		Move(&textRGB, 0, 0, w, h, 840,  170,100, 30);
    		Move(&textYUV, 0, 0, w, h, 840,  210, 100,30);
    		Move(&imageInfo, 0, 0, w, h, 840,  50,100, 30);
    		Move(&scaleInfo, 0, 0, w, h, 840,  90, 100,30);
    		Move(GetDlgItem(IDC_BAR1), 0, 0, w, h, 801,  0, 2,1000);
    		Move(GetDlgItem(IDC_BAR2), 0, 0, w, h, 803,  250, 197,2);
    		m_player.Invalidate(FALSE);
    	}
    }

    2. 图像和显示控件的适配。

       图像要尽量大的显示在控件上面, 并保持宽高比。

     

     这里分为两种情况:

      一: 图像宽高都比控件小。

           直接在控件中心位置显示图像。

      二: 图像的宽或高比控件大。

           分别计算图像宽度/控件宽度,  图像高度/控件高度。 取一个最大值,作为缩放比例。

           然后在控件中心位置显示图像。


    void CImageView::CalcImageShowRect(const CRect& rc, const CRect& rcImage, CRect& rcShow)
    {
    	double dw= rcImage.Width()/(1.0*rc.Width());
    	double dh= rcImage.Height()/(1.0*rc.Height());
    	int cx = rc.Width()/2;
    	int cy = rc.Height()/2;
    	rcShow = rc;
    	if(dw< 1.0 && dh < 1.0)
    	{
    		rcShow.left = cx - rcImage.Width()/2;
    		rcShow.top = cy - rcImage.Height()/2;
    		rcShow.right = rcShow.left + rcImage.Width();
    		rcShow.bottom = rcShow.top + rcImage.Height();
    		scale = 1.0;
    	}
    	else 
    	{
    		double s = max(dw, dh);
    		double fw = rcImage.Width()/s;
    		double fh = rcImage.Height()/s;
    		rcShow.left = cx - fw/2;
    		rcShow.right = cx + fw/2;
    		rcShow.top = cy - fh/2;
    		rcShow.bottom = cy + fh/2;
    
    	}
    }


    3. 以鼠标点为中心, 滚轮缩放图片。

    4. 鼠标拖动图片。

    5。双击100%显示图片, 再次双击显示全图

       对话框响应滚轮事件然后传给控件。

       上面计算过的控件显示区域, 是不变的。 我们修改图像的显示区域来实现缩放功能。



    先把坐标点从屏幕坐标系 映射到图像坐标系。

    void CImagePlayer::ScreenToImage(CPoint& pt)
    {
    	CPoint ret;
    	ret.x = rcImage.left + rcImage.Width()*(pt.x-rcShow.left)/rcShow.Width();
    	ret.y = rcImage.top + rcImage.Height()*(pt.y-rcShow.top)/rcShow.Height();
    	pt = ret;
    }


    定义一个scale变量来记录缩放倍数。

    比如scale=2,那么 新的显示宽度=图像宽度/2.

    由于缩放前后, 图像坐标系里的鼠标点离左右显示边界的距离是不变的。

    推出

      (鼠标点横坐标-新的左边界)/新的宽度 = ((鼠标点横坐标-旧的左边界)/旧的宽度。


    我们要求的是新的左边界, 其他参数已知。


    void CImagePlayer::Scale(CPoint pt)
    {
    	if(scale == 1.0)
    	{
    		rcImage = CRect(0, 0, w, h);
    	}
    	else
    	{
    		ScreenToImage(pt);
    		double dw = w/scale;
    		double dh = h/scale;
    		double ds = dw/rcImage.Width();
    		rcImage.left = pt.x - ds*(pt.x-rcImage.left);
    		rcImage.right = rcImage.left + dw;
    		rcImage.top = pt.y - ds*(pt.y-rcImage.top);
    		rcImage.bottom = rcImage.top + dh;
    		if(rcImage.left < 0) rcImage.left = 0;
    		if(rcImage.top < 0) rcImage.top = 0;
    		if(rcImage.bottom > h) rcImage.bottom = h;
    		if(rcImage.right > w) rcImage.right = w;
    	}
    	SendScaleInfo();
    	Invalidate(FALSE);
    
    }

    效果图:





    6. 图像任意角度旋转。

       图像旋转其实是很普通的几何问题。

       旋转矩阵:

       

        


    OPENCV提供了计算旋转矩阵的函数, 和仿射变换函数

    //! warps the image using affine transformation
    CV_EXPORTS_W void warpAffine( InputArray src, OutputArray dst,
                                  InputArray M, Size dsize,
                                  int flags=INTER_LINEAR,
                                  int borderMode=BORDER_CONSTANT,
                                  const Scalar& borderValue=Scalar());

    我的实现如下:

    void rotateImage(Mat& img, double degree, int &w, int &h)
    {
    	double angle = degree  * CV_PI / 180.;
    	double a = sin(angle), b = cos(angle);   
    	int width = img.cols;    
    	int height = img.rows;    
    	w= int(height * fabs(a) + width * fabs(b));    
    	h= int(width * fabs(a) + height * fabs(b));   
    
    	w = ALIGN_UP(w, 4);
    	h = ALIGN_UP(h, 4);
    	float map[6];  
    	CvMat map_matrix = cvMat(2, 3, CV_32F, map);    
    
    	CvPoint2D32f center = cvPoint2D32f(width / 2, height / 2);    
    	cv2DRotationMatrix(center, degree, 1.0, &map_matrix);    
    	map[2] += (w - width) / 2;    
    	map[5] += (h - height) / 2;
    	warpAffine(img, img, Mat(&map_matrix), Size(w, h),
    		CV_INTER_LINEAR | CV_WARP_FILL_OUTLIERS,BORDER_CONSTANT, Scalar::all(0));
    
    }


  • 相关阅读:
    温故知新-多线程-深入刨析park、unpark
    温故知新-多线程-forkjoin、CountDownLatch、CyclicBarrier、Semaphore用法
    温故知新-多线程-Cache Line存在验证
    CSS3动画基础
    通过DataSourceTransactionManager实现Spring事务
    MAC终端SSL_ERROR_SYSCALL in connection to XX
    磨刀不误砍柴工——ubuntu、mac终端美化
    k8s可视化工具kubernetes-dashboard部署——小白教程
    阿里云ECS(Ubuntu)单节点Kubernetes部署——小白教程
    Vue时间线组件
  • 原文地址:https://www.cnblogs.com/xinyuyuanm/p/3177825.html
Copyright © 2020-2023  润新知