精华内容
下载资源
问答
  • mat
    千次阅读
    2021-12-01 14:43:07

    OpenCV像素遍历常用的是三种方法:ptr指针,迭代器(iterator)以及动态地址at。

    • 动态地址at不适合用于像素遍历,速度太慢了,比较适合随机访问的方式;
    • 使用Mat的ptr指针进行图像遍历更加高效,

    特别的:一般图像行与行之间往往存储是不连续的,但是有些图像可以是连续的,Mat提供了一个检测图像是否连续的函数isContinuous()。当图像连通时,我们就可以把图像完全展开,看成是一行进行处理。

    因此最高效的遍历方法如下

    void image_copy(cv::Mat &src, cv::Mat &dst) {
        int h = src.rows;
        int w = src.cols;
        dst.create(src.size(), src.type());
        if (src.isContinuous() && dst.isContinuous()) {
            h = 1;
            w = w * src.rows * src.channels();
        }
        for (int i = 0; i < h; i++) {
            uchar *sptr = src.ptr<uchar>(i);
            uchar *dptr = dst.ptr<uchar>(i);
            for (int j = 0; j < w; j++) {
                *dptr++ = *sptr++;
                //dptr[j] = sptr[j];
            }
        }
    }

     PS:一般经过裁剪的Mat图像,都不再连续了,如cv::Mat crop_img = src(rect);crop_img 是不连续的Mat图像,如果想转为连续的,最简单的方法,就是将不连续的crop_img 重新clone()一份给新的Mat就是连续的了。关于Mat连续存储的问题,可见:http://blog.csdn.net/guyuealian/article/details/78614662
     

    其他遍历方式 ,可参考:

    实现方式: https://blog.csdn.net/keith_bb/article/details/53071133

    
    void image_copy1(cv::Mat &src, cv::Mat &dst) {
        //使用ptr指针
        int n = src.channels();
        int h = src.rows;          //获取图像矩阵行数
        int w = src.cols;          //获取图像矩阵列数
        dst.create(src.size(), src.type()); //初始化返回结果
        for (int i = 0; i < h; i++) {
            //获取矩阵每行首地址指针
            uchar *sptr = src.ptr<uchar>(i);
            uchar *dptr = dst.ptr<uchar>(i);
            for (int j = 0; j < w; j++) {
                uchar b = sptr[n * j];
                uchar g = sptr[n * j + 1];
                uchar r = sptr[n * j + 2];
                dptr[n * j] = b;
                dptr[n * j + 1] = g;
                dptr[n * j + 2] = r;
            }
        }
    }
    
    void image_copy2(cv::Mat &src, cv::Mat &dst) {
        //使用ptr指针
        int n = src.channels();
        int h = src.rows;              //获取图像矩阵行数
        int w = src.cols * n;          //三通道图像每行元素个数为列数x通道数
        dst.create(src.size(), src.type());
        for (int i = 0; i < h; i++) {
            //获取矩阵每行首地址指针
            uchar *sptr = src.ptr<uchar>(i);
            uchar *dptr = dst.ptr<uchar>(i);
            for (int j = 0; j < w; j++) {
                dptr[j] = sptr[j];
            }
        }
    }
    
    void image_copy3(cv::Mat &src, cv::Mat &dst) {
        //使用ptr指针
        int n = src.channels();
        int h = src.rows;              //获取图像矩阵行数
        int w = src.cols * n;          //三通道图像每行元素个数为列数x通道数
        dst.create(src.size(), src.type());
        for (int i = 0; i < h; i++) {
            //获取矩阵每行首地址指针
            uchar *sptr = src.ptr<uchar>(i);
            uchar *dptr = dst.ptr<uchar>(i);
            for (int j = 0; j < w; j += n) {
                //uchar b = sptr[j];
                //uchar g = sptr[j + 1];
                //uchar r = sptr[j + 2];
                uchar b = *sptr++;
                uchar g = *sptr++;
                uchar r = *sptr++;
                dptr[j] = b;
                dptr[j + 1] = g;
                dptr[j + 2] = r;
            }
        }
    }
    
    void image_copy(cv::Mat &src, cv::Mat &dst) {
        int h = src.rows;
        int w = src.cols;
        dst.create(src.size(), src.type());
        if (src.isContinuous() && dst.isContinuous()) {
            h = 1;
            w = w * src.rows * src.channels();
        }
        for (int i = 0; i < h; i++) {
            uchar *sptr = src.ptr<uchar>(i);
            uchar *dptr = dst.ptr<uchar>(i);
            for (int j = 0; j < w; j++) {
                *dptr++ = *sptr++;
                //dptr[j] = sptr[j];
            }
        }
    }
    


    以下是图像融合的算法:

    (1)这是完全使用OpenCV的接口实现的图像融合,循环5次耗时30.29811 ms

    
    void image_fusion(cv::Mat &imgBGR, cv::Mat matte, cv::Mat &out, cv::Mat bg) {
        if (matte.channels() == 1) {
            matte.convertTo(matte, CV_32FC1, 1.0 / 255, 0);
            cv::cvtColor(matte, matte, cv::COLOR_GRAY2BGR);
        } else {
            matte.convertTo(matte, CV_32FC3, 1.0 / 255, 0);
        }
        //out = imgBGR.clone();
        vector<float> ratio{(float) imgBGR.cols / bg.cols, (float) imgBGR.rows / bg.rows};
        float max_ratio = *max_element(ratio.begin(), ratio.end());
        if (max_ratio > 1.0) {
            cv::resize(bg, bg, cv::Size(int(bg.cols * max_ratio), int(bg.rows * max_ratio)));
        }
        bg = image_center_crop(bg, imgBGR.cols, imgBGR.rows);
        bg.convertTo(bg, CV_32FC3, 1, 0);
        imgBGR.convertTo(out, CV_32FC3, 1, 0);
        // Fix a Bug: 1 - alpha实质上仅有B通道参与计算,多通道时(B,G,R),需改Scalar(1.0, 1.0, 1.0)-alpha
        // out = out.mul(alpha) + bgi.mul(1 - alpha);
        out = out.mul(matte) + bg.mul(cv::Scalar(1.0, 1.0, 1.0) - matte);
        out.convertTo(out, CV_8UC3, 1, 0);
    }
    

    (2)这是通过遍历的方式实现的图像融合,循环5次耗时24.44169 ms

    注意到matte需要除以255,把它放在循环体外进行乘法和除法运算,可以明显加快
    
    void image_fusion_fast(cv::Mat &imgBGR, cv::Mat matte, cv::Mat &out, cv::Mat bg) {
        assert(matte.channels() == 1);
        out.create(imgBGR.size(), CV_8UC3);
        vector<float> ratio{(float) imgBGR.cols / bg.cols, (float) imgBGR.rows / bg.rows};
        float max_ratio = *max_element(ratio.begin(), ratio.end());
        if (max_ratio > 1.0) {
            cv::resize(bg, bg, cv::Size(int(bg.cols * max_ratio), int(bg.rows * max_ratio)));
        }
        bg = image_center_crop(bg, imgBGR.cols, imgBGR.rows);
        int h = imgBGR.rows;
        int w = imgBGR.cols;
        int n = imgBGR.channels();
        // 循环体外进行乘法和除法运算
        matte.convertTo(matte, CV_32FC1, 1.0 / 255, 0);
        for (int i = 0; i < h; ++i) {
            uchar *sptr = imgBGR.ptr<uchar>(i);
            uchar *dptr = out.ptr<uchar>(i);
            float *mptr = matte.ptr<float>(i);
            uchar *bptr = bg.ptr<uchar>(i);
            for (int j = 0; j < w; ++j) {
                //float alpha = mptr[j] / 255; //循环体尽量减少乘法和除法运算
                float alpha = mptr[j];
                float _alpha = 1.f - alpha;
                dptr[n * j] = uchar(sptr[n * j] * alpha + bptr[n * j] * _alpha);
                dptr[n * j + 1] = uchar(sptr[n * j + 1] * alpha + bptr[n * j + 1] * _alpha);
                dptr[n * j + 2] = uchar(sptr[n * j + 2] * alpha + bptr[n * j + 2] * _alpha);
            }
        }
    }

    (3)如果输入的Mat都是连续存储的,则可以转换为向量的形式进行遍历,循环5次耗时23.10372ms

    
    void image_fusion_fast(cv::Mat &imgBGR, cv::Mat matte, cv::Mat &out, cv::Mat bg) {
        assert(matte.channels() == 1);
        out.create(imgBGR.size(), CV_8UC3);
        vector<float> ratio{(float) imgBGR.cols / bg.cols, (float) imgBGR.rows / bg.rows};
        float max_ratio = *max_element(ratio.begin(), ratio.end());
        if (max_ratio > 1.0) {
            cv::resize(bg, bg, cv::Size(int(bg.cols * max_ratio), int(bg.rows * max_ratio)));
        }
        bg = image_center_crop(bg, imgBGR.cols, imgBGR.rows);
        int n = imgBGR.channels();
        int h = imgBGR.rows;
        int w = imgBGR.cols * n;
        // 循环体外进行乘法和除法运算
        matte.convertTo(matte, CV_32FC1, 1.0 / 255, 0);
        for (int i = 0; i < h; ++i) {
            uchar *sptr = imgBGR.ptr<uchar>(i);
            uchar *dptr = out.ptr<uchar>(i);
            float *mptr = matte.ptr<float>(i);
            uchar *bptr = bg.ptr<uchar>(i);
            for (int j = 0; j < w; j += n) {
                //float alpha = mptr[j] / 255; //循环体尽量减少乘法和除法运算
                float alpha = mptr[j / 3];
                float _alpha = 1.f - alpha;
                dptr[j] = uchar(sptr[j] * alpha + bptr[j] * _alpha);
                dptr[j + 1] = uchar(sptr[j + 1] * alpha + bptr[j + 1] * _alpha);
                dptr[j + 2] = uchar(sptr[j + 2] * alpha + bptr[j + 2] * _alpha);
            }
        }
    }
    
    
    
    
    

    (3)这是通过遍历的方式,去除了循环体内大部分乘法,实现的图像融合,循环5次耗时23.10372ms

    
    void image_fusion_fast(cv::Mat &imgBGR, cv::Mat matte, cv::Mat &out, cv::Mat bg) {
        assert(matte.channels() == 1);
        out.create(imgBGR.size(), CV_8UC3);
        vector<float> ratio{(float) imgBGR.cols / bg.cols, (float) imgBGR.rows / bg.rows};
        float max_ratio = *max_element(ratio.begin(), ratio.end());
        if (max_ratio > 1.0) {
            cv::resize(bg, bg, cv::Size(int(bg.cols * max_ratio), int(bg.rows * max_ratio)));
        }
        bg = image_center_crop(bg, imgBGR.cols, imgBGR.rows);
        int n = imgBGR.channels();
        int w = imgBGR.cols * imgBGR.rows * n;
        // 循环体外进行乘法和除法运算
        matte.convertTo(matte, CV_32FC3, 1.0 / 255, 0);
        uchar *sptr = imgBGR.ptr<uchar>(0);
        uchar *dptr = out.ptr<uchar>(0);
        float *mptr = matte.ptr<float>(0);
        uchar *bptr = bg.ptr<uchar>(0);
        for (int j = 0; j < w; j += n) {
            //float alpha = mptr[j] / 255; //循环体尽量减少乘法和除法运算
            float alpha = mptr[j / 3];
            float _alpha = 1.f - alpha;
            dptr[j] = uchar(sptr[j] * alpha + bptr[j] * _alpha);
            dptr[j + 1] = uchar(sptr[j + 1] * alpha + bptr[j + 1] * _alpha);
            dptr[j + 2] = uchar(sptr[j + 2] * alpha + bptr[j + 2] * _alpha);
        }
    }

    更多相关内容
  • MAT.jl:用于读取MATLAB文件的Julia模块
  • C# Bitmap转为Mat

    2018-11-19 16:53:57
    C#语言下,官方好像没有提供直接的方式把Bitmap转为Mat,但是可以使用我的这个方式转变格式
  • uci数据集mat格式

    2019-04-09 03:05:45
    常见的UCI数据集,均为mat格式版,可直接在matlab使用
  • 相比《Halcon12 HObject与VC++ OpenCV Mat相互转换》 本人亲测比HObject Mat2HObject(Mat& image)快4倍 比Mat HObject2Mat(HObject Hobj)快7倍
  • 在mfc中picture控件中显示Mat图片

    热门讨论 2015-08-17 10:38:13
    将opencv中的Mat格式的图片显示在mfc中的picture控件上,该程序已经被放在了一个函数中间,只需调用该函数ShowMatImgToWnd(CWnd* pWnd, cv::Mat img)就可以将所需的图片显示在picture控件上了,其中CWnd* pWnd参数中...
  • 1.包含各类数据集 2.数据集的格式有mat,txt,data形式 3.机器学习必备数据集
  • 在matlab中将txt文件转换为mat格式文件
  • 将内存中YUV数据(char* pBuf,int nLen)转成opencv的Mat格式,RGB显示
  • OpenCV Java入门三 Mat的基本操作

    千次阅读 2022-03-24 13:33:20
    } public static Mat bufferedImageToMat(BufferedImage bi) { Mat mat = new Mat(bi.getHeight(), bi.getWidth(), CvType.CV_8UC3); byte[] data = ((DataBufferByte) bi.getRaster().getDataBuffer()).get...

    环境好了,我们就可以进入正文了。

    在之前入门一、二中分别已经有画图的两个例子了。但没有细节展开我们的代码和OpenCV到底在干什么。

    使用OpenCV时你需要补充的知识

    你需要熟练使用Java Swing,或者是其它任何一门语言中关于GUI方面的编程。

    我们这用的是OpenCV Java,因此对于Java Swing必须熟练。你可以安装eclipse 中的windowbuilder来帮助你做Swing的编程。

    至于Java Swing中的界面、Frame、Panel、Button以及Layout,这块在“JDK核心技术卷1、卷2”中已有详细描述,我就不多此一举了。

    Mat对象

    OpenCV用来存储图像,很多时候都会用到这个Mat方法。数字图像可看做一个数值矩阵, 其中的每一个元素表明一个像素点。Mat在 OpenCV 中表示的是 N 维稠密矩阵,与稠密矩阵相对的是稀疏矩阵(只存储非零的像素值)。

    Mat 类包含两部分,一是 矩阵头 (matrix header),二是 矩阵指针 (pointer to matrix),部分矩阵头以下:blog

    int  flags;  // signaling the contents of the matrix
    int  dims;   // dimensions
    int  rows, cols;  // rows and columns
    MatSize  size;  //
    MatStep  step;  //

    具体不作进一步展开,但我们要会使用这个Mat。

    因此今天以Mat来做几个小练习。

    Mat划线

    package org.mk.opencv;
    
    import org.opencv.core.Core;
    import org.opencv.core.CvType;
    import org.opencv.core.Mat;
    import org.opencv.highgui.HighGui;
    
    public class DrawLine {
    
    	public static void main(String[] args) {
    		// 载入dll(必须先加载)
    		System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
    		Mat truth = new Mat(500, 500, CvType.CV_8UC3);
    
    		byte[] line = new byte[truth.channels() * truth.width()];
    
    		for (int i = 0; i < line.length; i++) {
    			line[i] = 125;
    		}
    		truth.put(250, 0, line);
    
    		HighGui.imshow("原图", truth);
    		HighGui.waitKey(0);
    
    	}
    
    }
    

    记得OpenCV上手都有一句“System.loadLibrary(Core.NATIVE_LIBRARY_NAME);”,是因为OpenCV Java虽然使用的是“opencv-343.jar”,实际它会去调用“opencv_java343.dll”,并且opencv_java343.dll有依赖,它会去找它自己在Windows的控制面板->系统变量->path中的依赖的那些opencv编译出来的包。

    我不喜欢把opencv_java343.dll所依赖的这些DLL放到windows的安装目录的System32目录下。

    因为你把这些dll放在system32目录下,和你直接在System的path下加入这些dll效果是一样的。

     

    HighGui是一个OpenCV自带的“内嵌面板”。

    有时我也会自己写JFrame来做“展示”。如下面这个例子。

    Mat在己有图片上加圆圈

    ImageShowAddCircle.java

    package org.mk.opencv;
    
    import org.opencv.core.Core;
    import org.opencv.core.Mat;
    import org.opencv.imgcodecs.Imgcodecs;
    
    public class ImageShowAddCircle {
    	public static void main(String[] args) {
    		// 载入dll(必须先加载)
    		System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
    		// 将文件读入为OpenCV的Mat格式。注意测试时,路径不要包括中文
    		Mat src = Imgcodecs.imread("D:\\opencv-demo\\1.jpg");
    		if (src.dataAddr() == 0) {
    			System.out.println("打开文件出错");
    		}
    		ImageViewerAddCircle imageViewer = new ImageViewerAddCircle(src, "图片上加圆圈");
    		imageViewer.imshow();
    	}
    }
    

     ImageViewer.java

    package org.mk.opencv;
    
    import java.awt.BorderLayout;
    import java.awt.Dimension;
    import java.awt.Image;
    
    import javax.swing.ImageIcon;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JScrollPane;
    import javax.swing.UIManager;
    import javax.swing.UnsupportedLookAndFeelException;
    import javax.swing.WindowConstants;
    
    import org.mk.opencv.util.OpenCVUtil;
    import org.opencv.core.Mat;
    import org.opencv.core.Point;
    import org.opencv.core.Scalar;
    import org.opencv.imgproc.Imgproc;
    
    public class ImageViewerAddCircle {
    	private JLabel imageView;
    	private Mat image;
    	private String windowName;
    
    
    	public ImageViewerAddCircle(Mat image) {
    		this.image = image;
    	}
    
    	/**
    	 * @param image      要显示的mat
    	 * @param windowName 窗口标题
    	 */
    	public ImageViewerAddCircle(Mat image, String windowName) {
    		this.image = image;
    		this.windowName = windowName;
    	}
    
    	/**
    	 * 图片显示,并使用opencv的ImgProc.circle在图片上加两个圆圈
    	 */
    	public void imshow() {
    		setSystemLookAndFeel();
    		//在图上画圆
    		Imgproc.circle(image, new Point(50, 50), 40, new Scalar(255, 0, 0), 2);
    		//在图上画另一个圆
    		Imgproc.circle(image, new Point(50, 100), 80, new Scalar(0, 255, 0), 5);
    		//展示画了圆的图像
    		Image loadedImage = OpenCVUtil.matToImage(image);
    		JFrame frame = createJFrame(windowName, image.width(), image.height());
    		imageView.setIcon(new ImageIcon(loadedImage));
    		frame.pack();
    		frame.setLocationRelativeTo(null);
    		frame.setVisible(true);
    		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);// 用户点击窗口关闭
    	}
    
    	private void setSystemLookAndFeel() {
    		try {
    			UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
    		} catch (ClassNotFoundException e) {
    			e.printStackTrace();
    		} catch (InstantiationException e) {
    			e.printStackTrace();
    		} catch (IllegalAccessException e) {
    			e.printStackTrace();
    		} catch (UnsupportedLookAndFeelException e) {
    			e.printStackTrace();
    		}
    	}
    
    	private JFrame createJFrame(String windowName, int width, int height) {
    		JFrame frame = new JFrame(windowName);
    		imageView = new JLabel();
    		final JScrollPane imageScrollPane = new JScrollPane(imageView);
    		imageScrollPane.setPreferredSize(new Dimension(width, height));
    		frame.add(imageScrollPane, BorderLayout.CENTER);
    		frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    		return frame;
    	}
    }
    

    它显示的效果如下:

    它会在一个图片上(未加圆圈前)

     显示带两个圆圈的画(加了圆圈后)

     Mat与Image互转

    由于我们经常使用Swing组件,Swing中有一个imageView.setIcon方法或者是setImage方法,它要求的是输入一个java.awt.Image对象。

    那么Mat和Image经常会互转,因此我们有一套互转的小工具类如下:

    OpenCVUtil.java

    package org.mk.opencv.util;
    
    import java.awt.Image;
    import java.awt.image.BufferedImage;
    import java.awt.image.DataBufferByte;
    import java.util.ArrayList;
    import java.util.LinkedList;
    import java.util.List;
    import java.io.File;
    
    import org.apache.log4j.Logger;
    import org.opencv.core.CvType;
    import org.opencv.core.Mat;
    
    
    public class OpenCVUtil {
    	private static Logger logger = Logger.getLogger(OpenCVUtil.class);
    
    	public static Image matToImage(Mat matrix) {
    		int type = BufferedImage.TYPE_BYTE_GRAY;
    		if (matrix.channels() > 1) {
    			type = BufferedImage.TYPE_3BYTE_BGR;
    		}
    		int bufferSize = matrix.channels() * matrix.cols() * matrix.rows();
    		byte[] buffer = new byte[bufferSize];
    		matrix.get(0, 0, buffer); // 获取所有的像素点
    		BufferedImage image = new BufferedImage(matrix.cols(), matrix.rows(), type);
    		final byte[] targetPixels = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();
    		System.arraycopy(buffer, 0, targetPixels, 0, buffer.length);
    		return image;
    	}
    
    
    	public static BufferedImage matToBufferedImage(Mat matrix) {
    		int cols = matrix.cols();
    		int rows = matrix.rows();
    		int elemSize = (int) matrix.elemSize();
    		byte[] data = new byte[cols * rows * elemSize];
    		int type;
    		matrix.get(0, 0, data);
    		switch (matrix.channels()) {
    		case 1:
    			type = BufferedImage.TYPE_BYTE_GRAY;
    			break;
    		case 3:
    			type = BufferedImage.TYPE_3BYTE_BGR;
    			// bgr to rgb
    			byte b;
    			for (int i = 0; i < data.length; i = i + 3) {
    				b = data[i];
    				data[i] = data[i + 2];
    				data[i + 2] = b;
    			}
    			break;
    		default:
    			return null;
    		}
    		BufferedImage image2 = new BufferedImage(cols, rows, type);
    		image2.getRaster().setDataElements(0, 0, cols, rows, data);
    		return image2;
    	}
    
    	public static Mat bufferedImageToMat(BufferedImage bi) {
    		Mat mat = new Mat(bi.getHeight(), bi.getWidth(), CvType.CV_8UC3);
    		byte[] data = ((DataBufferByte) bi.getRaster().getDataBuffer()).getData();
    		mat.put(0, 0, data);
    		return mat;
    	}
    }
    

    Mat使用blur图片

    package org.mk.opencv;
    
    import org.opencv.core.Core;
    import org.opencv.core.Mat;
    import org.opencv.core.Size;
    import org.opencv.imgcodecs.Imgcodecs;
    import org.opencv.imgproc.Imgproc;
    
    public class Blur {
    	public static void main(String[] args) {
    		try {
    			System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
    
    			Mat src = Imgcodecs.imread("D:/opencv-demo/1.jpg");
    			if (src.empty()) {
    				throw new Exception("no file");
    			}
    
    			Mat dst = src.clone();
    
    			Imgproc.blur(src, dst, new Size(800, 600));
    			Imgcodecs.imwrite("D:/opencv-demo/blur.jpg", dst);
    		} catch (Exception e) {
    			System.out.println("出错啦:" + e);
    		}
    	}
    
    }
    

    它把一张原来的未blur处理的图片,变成了如下这样

     结束今天的博客,下一篇会讲“认脸”。认脸和识脸是两个课题,我们一步步来。目前网上99%的教程只能到达认脸这一步,即这是一个脸。但不代表这是谁?这是谁就叫“识脸”。

    展开全文
  • mnist_uint8.mat下载

    热门讨论 2017-01-01 22:23:58
    手写数字集 MNIST 使用matlab处理后得到的mnist_uint8.mat数据。 数据为uint8类型的图像像素数据,包含train_x,train_y,test_x,test_y, 每项都是一行向量的方式存储的。
  • labview读取mat文件

    2014-04-28 15:39:14
    mat文件中的数据用labview打开,mat数据可以是一个变量,也可以是多个变量。均可用MATLAB节点打开。用二维数组显示。
  • OpenCV 学习笔记day3-Mat对象与创建一 ,拷贝函数:“=” 浅拷贝Mat::cloneMat::copyTo二,创建空白图像函数:Mat::zeros() 返回指定大小和类型的零数组Mat::ones() 返回指定大小和类型全为1的数组Mat::cols 行数Mat...

    day3-Mat对象与创建

    Mat类的基本操作

    Mat类的成员函数:Mat::clone(),Mat::copyTo(),Mat::zeros(),Mat::ones(),Scalar()

    一 ,拷贝

    函数:

    1. “=” 浅拷贝

    浅拷贝 - 不复制数据只创建矩阵头,数据共享

    例1

    Mat a = imread("1.jpg");
    
    1. Mat::clone

    clone 是完全的深拷贝,在内存中申请新的空间

    //定义
    Mat Mat::clone() const
    {
        Mat m;
        copyTo(m);
        return m;
    }
    

    例2

    Mat m1 = image.clone();
    //clone 是完全的深拷贝,在内存中申请新的空间,与image独立
    
    1. Mat::copyTo

    //定义
    void GpuMat::copyTo(OutputArray dst, InputArray mask) const
    {
        copyTo(dst, mask, Stream::Null());
    }
    

    OpenCV中image.copyTo()有两种形式:

    1、image.copyTo(imageROI),作用是把image的内容粘贴到imageROI;

    2、image.copyTo(imageROI,mask),作用是把mask和image重叠以后把mask中像素值为0(black)的点对应的image中的点变为透明,而保留其他点。

    mask:即掩模。掩模是由0和1组成的一个二进制图像。当在某一功能中应用掩模时,1值区域被处理,被屏蔽的0值区域不被包括在计算中。通过指定的数据值、数据范围、有限或无限值、感兴趣区和注释文件来定义图像掩模,也可以应用上述选项的任意组合作为输入来建立掩模。

    例3

    image.copyTo(m2);//把image的内容拷贝到m2中
    

    二,创建空白图像

    函数:

    1. Mat::zeros() 返回指定大小和类型的零数组

      Mat::ones() 返回指定大小和类型全为1的数组

    //定义
    static MatExpr zeros(Size size, int type);
    static MatExpr ones(Size size, int type);
    

    type可以是任何的预定义类型,预定义类型的结构如下所示:
    CV_<bit_depth>(S|U|F)C<number_of_channels>
    1)bit_depth—比特数—代表8bite,16bites,32bites,64bites—举个例子吧–比如说,如
    如果你现在创建了一个存储–灰度图片的Mat对象,这个图像的大小为宽100,高100,那么,现在这张灰度图片中有10000个像素点,它每一个像素点在内存空间所占的空间大小是8bite,8位–所以它对应的就是CV_8

    2)S|U|F
    S–代表—signed int—有符号整形
    U–代表–unsigned int–无符号整形
    F–代表–float---------单精度浮点型

    3)C<number_of_channels>
    代表—一张图片的通道数,比如:
    1–灰度图片–grayImg—是–单通道图像
    2–RGB彩色图像---------是–3通道图像
    3–带Alph通道的RGB图像–是--4通道图像

    例4

    Mat m3 = Mat::zeros(Size(8, 8), CV_8UC1);
    //创建矩阵;CV_8UC1八位无符号单通道 CV_8UC1单通道
    //初始化为1 此时只能选择使用单通道 
    //if使用3通道看下面完整结果会有错误-只有第一通道初始化为1
    Mat m3 = Mat::ones(Size(8, 8), CV_8UC1);//8*8 8位无符号单通道
    //初始化为1,使用3通道
    Mat m3 = Mat::ones(Size(8, 8), CV_8UC3);//8*8 8位无符号3通道
    
    1. Mat::cols 行数

      Mat::rows 列数

      Mat::channels 通道数

    例5

    std::cout << "width: " << m3.cols << std::endl;//输出宽度
    	std::cout << "height: " <<m3.rows << std::endl;//输出宽度
    	std::cout << "channels: " << m3.channels()<< std::endl;//输出通道数
    

    代码

    quickopencv.h

    #pragma once
    
    #include <opencv2\highgui.hpp>
    
    #include <opencv2\imgproc.hpp>
    
    using namespace cv;
    //定义类
    class QuickDemo{
    public:
    	void colorSpace_Demo(Mat &image);//色彩空间转换函数2021-12-24
    	void mat_creation_demo(Mat &image);//Mat对象与创建2021-12-27
    };
    

    OpencvTest.cpp

    #include <iostream>
    #include <opencv2\highgui.hpp>
    #include <opencv2\imgproc.hpp>
    #include<quickopencv.h>
    
    using namespace cv;
    using namespace std;
    
    
    int main()
    {
    	Mat scr = imread("D:\\学习\\OpenCV学习\\pictures\\image\\1.jpg");//打开一张图
    	if (!scr.data == 1)//判空
    		return -1;
    	namedWindow("窗口1", WINDOW_NORMAL);//创建 WINDOW_FREERATIO窗口
    	imshow("窗口1",scr);//在创建的窗口显示
    	QuickDemo qd;
    	//qd.colorSpace_Demo(scr);//色彩转换
    	//waitKey(0);//延时 0->一直延时 1->延时1ms
    	qd.mat_creation_demo(scr);//Mat类的相关操作
    	waitKey(0);
    	return 0;
    

    QuickDemo.cpp

    #include <opencv2\highgui.hpp>
    
    #include <opencv2\imgproc.hpp>
    
    #include<quickopencv.h>
    
    #include <iostream>
    // 函数名称:void QuickDemo::mat_creation_demo(Mat &image)
    // 功能说明:Mat对象与创建
    // 参数说明:Mat &image
    // 函数返回:无
    // 修改时间:2021年12月29日
    // 备    注:
    void QuickDemo::mat_creation_demo(Mat &image)
    {
    	//创建空白图像 
    	//8*8 8位无符号1通道 全部初始化为0
    	Mat m3 = Mat::zeros(Size(8, 8), CV_8UC1);//矩阵;size:8*8 CV_8UC1:八位无符号单通道 初始化为0---显示结果1	
    	//Mat m3 = Mat::zeros(Size(8, 8), CV_8UC3);//CV_8UC3八位无符号3通道--显示结果2
    	
    	//初始化为1 此时只能选择使用单通道 if使用3通道看以下结果会有错误
    	//Mat m3 = Mat::ones(Size(8, 8), CV_8UC1);//szie:8*8 CV_8UC1:8位无符号单通道 初始化为0--显示结果3
    	//Mat m3 = Mat::ones(Size(8, 8), CV_8UC3);//size:8*8 CV_8UC3:8位无符号3通道 初始化为1--显示结果4 只能初始化第一通道
    	std::cout << "width: " << m3.cols << std::endl;//输出宽度
    	std::cout << "height: " <<m3.rows << std::endl;//输出宽度
    	std::cout << "channels: " << m3.channels()<< std::endl;//输出通道数
    	std::cout << m3 << std::endl;//输出m3
    }
    

    显示结果1
    在这里插入图片描述
    显示结果2
    在这里插入图片描述
    显示结果3
    初始化为1单通道
    显示结果4-只能初始化第一通道
    初始化为1 3通道 错误

    三 ,赋值操作

    函数:

    1. Scalar() 给三个通道赋值

    //定义
    Scalar_<_Tp>::Scalar_(_Tp v0, _Tp v1, _Tp v2, _Tp v3)
    {
        this->val[0] = v0;
        this->val[1] = v1;
        this->val[2] = v2;
        this->val[3] = v3;
    }
    

    例6

    m4 = Scalar(127,127,127);//给3个通道都赋值 灰度图 
    //127为灰度值
    m4 = Scalar(255, 0, 0);
    //300*300 3通道的灰度(127,127,127),
    //蓝色(255,0,0),绿色(0,255,0),黄色(0,0,255)
    

    代码

    quickopencv.h

    #pragma once
    
    #include <opencv2\highgui.hpp>
    
    #include <opencv2\imgproc.hpp>
    
    using namespace cv;
    //定义类
    class QuickDemo{
    public:
    	void colorSpace_Demo(Mat &image);//色彩空间转换函数2021-12-24
    	void mat_creation_demo(Mat &image);//Mat对象与创建2021-12-27
    };
    

    OpencvTest.cpp

    #include <iostream>
    #include <opencv2\highgui.hpp>
    #include <opencv2\imgproc.hpp>
    #include<quickopencv.h>
    
    using namespace cv;
    using namespace std;
    
    
    int main()
    {
    	Mat scr = imread("D:\\学习\\OpenCV学习\\pictures\\image\\1.jpg");//打开一张图
    	if (!scr.data == 1)//判空
    		return -1;
    	namedWindow("窗口1", WINDOW_NORMAL);//创建 WINDOW_FREERATIO窗口
    	imshow("窗口1",scr);//在创建的窗口显示
    	QuickDemo qd;
    	//qd.colorSpace_Demo(scr);//色彩转换
    	//waitKey(0);//延时 0->一直延时 1->延时1ms
    	qd.mat_creation_demo(scr);//Mat类的相关操作
    	waitKey(0);
    	return 0;
    

    QuickDemo.cpp

    void QuickDemo::mat_creation_demo(Mat &image)
    {
    	//赋值操作
    	Mat m4=Mat::zeros(Size(300,300),CV_8UC3);
    	//m4 = 127;//此时只能给第一个通道赋值 127为灰度
    	//--显示结果5
    	//Scalar()函数
    	m4 = Scalar(127,127,127);//给3个通道都赋值 灰度图--结果6
    	//m4 = Scalar(255, 0, 0);//300*300 3通道的灰度(127,127,127),蓝色(255,0,0),绿色(0,255,0),黄色(0,0,255)--显示结果7
    	imshow("m4", m4);//可以用imshow输出显示 
    
    	//Mat m5 = m4;//m5指向了m4 //***
    	//m5 = Scalar(0, 255, 255);//此时修改了m4的颜色为黄色
    	//imshow("m4",m4);//m4输出显示为黄色--显示结果8
    
    	std::cout << "width: " << m4.cols << std::endl;//输出宽度
    	std::cout << "height: " <<m4.rows << std::endl;//输出宽度
    	std::cout << "channels: " << m4.channels()<< std::endl;//输出通道数
    	std::cout << m4 << std::endl;//输出m
    }
    

    结果5–只有第一个通道被赋值
    赋值给8位无符号3通道,只有第一个通道被赋值

    结果6.1–使用Scalar(),3个通道都赋值
    3个通道都赋值
    结果6.2–300*300 3通道的灰度图像
    300*300 3通道的灰度图像
    显示结果7.1
    红
    显示结果7.2
    绿
    显示结果7.3
    蓝
    显示结果8
    m4

    展开全文
  • C | 使用C语言读取.mat文件

    千次阅读 2022-04-28 15:05:45
    用C语言读.mat文件


    前言

    故事的开始,是一个菜鸡要开始做毕设。然后…为了实现用C语言度MATLAB的.mat文件,大概划了半个月的水…现在交完毕设终稿,就来整理一下啦!(虽然我猜后面可能也不一定要用C读.mat了23333)
    划水心路历程如下:stage1.先花了2-3天时间到处搜罗优秀网友们实现用C读取mat文件的实例,然后发现了matio;stage2.花了一个星期去调matio并且没有成功(;stage3.利用stage2的不完全版本算是实现了使用C读取.mat的目的。

    平台:MATLAB(生成.mat文件),Visual Studio 2022
    语言:MATLAB,C语言


    一、使用matio读取.mat文件

    matio是一个读取.mat文件的开源代码。
    官网里的东西还挺多的,除了各个版本的代码外,也有关于matio使用的user_guide(我后面基于调试matio的半成品实现功能,也有一部分是参考了这一份说明。)
    具体调试过程此处先挖坑,反正也是基于大佬博客的帮助,最后也是没有调处来orz。要是后面有心情的话再填坑= =(毕竟我不太记得了)
    以及确实是有很多人通过matio实现了这个功能(羡慕.jpg),但很多人里面都没有本菜鸡就是了hhh。毕竟自从大一也不怎么认真地学完C语言后,基本就没认真学过软件的编程了。

    1. matio_user_guide章节设置

    1. Introduction
       // 大概是对matio的介绍吧
    2. Quick Start
       // 关于如何用matio实现想要的功能的介绍,大致包括:打开/创建mat文件;读写mat文件
       2.1 Opening and Creating MAT Files
       2.2 Reading Variables in a MAT File
       2.3 Writing Variables
    3. Building matio
       // 大概是关于在各个平台如何使用matio的介绍
       3.1 Quick Build Guide
       3.2 Configure Options
       3.3 CMake build system
       3.4 Visual Studio
       3.5 Testsuite
    4. MATLAB Variable
       // 对可以读取的数据类型进行介绍。
       // double; matrix; cell; struct
    

    2. 下载地址

    matio下载地址: matio下载官网
    hdf5 下载地址: hdf5下载官网

    二、利用库文件在其他工程实现读取.mat

    可读取类型:double、matrix、cell、struct

    1.导入库和头文件

    关于Visual Studio如何导入外部库,因为有很多这方面的教程,这里先不多说。
    (依然是挖个坑,万一哪天打算填坑呢?

    #include "matio.h"		
    #pragma comment(lib,"libmatio.lib")
    #pragma comment(lib,"zlib.lib")
    #pragma comment(lib,"hdf5.lib")
    #pragma comment(lib,"libhdf5.lib")
    

    其中,zlib和hdf5主要是是在使用特殊格式的.mat文件时使用。
    如果要使用的只是普通的.mat文件,可以忽略这几个库(实测没有问题)。

    关于特殊格式的.mat文件,官方文档的说法是:
    m a t i o matio matio库可以创建 v e r s i o n _ 4 version\_4 version_4的MAT文件, v e r s i o n _ 5 version\_5 version_5的MAT文件,带有可变压缩的 v e r s i o n _ 5 version\_5 version_5的MAT文件(使用zlib构建),引入HDF5格式的MAT文件。(但是本人并没有研究过.mat这种格式的文件)

    2. 打开mat文件

    • 如何创建一个新的MAT 文件; Mat_CreatVer
    • 如何打开一个存在的MAT文件并进行读写访问; Mat_Open
    • 如何关闭一个MAT文件。 Mat_Close

    打开.mat文件的代码如下(以打开"xxx.mat"文件为例):
    (创建MAT文件的代码可见官方文档)

    void LoadStarData(void) {
    	// step1: 打开MAT文件
    	mat_t* matfp;
    	const char* file;		// MAT文件名
    	file = "xxx.mat";		// 打开工程路径下的.mat文件
    
    	matfp = Mat_Open(file, MAT_ACC_RDONLY);
    	if (NULL == matfp) {
    		printf("Error opening MAT file %s!\n", file);
    	}
    
    	// step2: 读取MAT文件中保存的数据(double、matrix、cell、struct)
    	// ``````
    	
    	// step3: 关闭MAT文件
    	Mat_Close(matfp);	
    }
    

    其中,读取数据的部分在step2位置进行,将在文章后面介绍。

    3. 读取matrix类型

    此处先说明:因为本人属实菜得一批,所以虽然知道一般情况下声明结构体之类的变量后都需要划空间,但属实不太会操作= =。同时本人的指针也学得一塌糊涂= =。希望等后面重新自学了C语言后可以更新一下代码吧QAQ

    读取matrix类型的数据(以打开xxx.mat里名为test的数组为例,test为3x3数组)

    void LoadStarData(void) {
    	// step1: 打开MAT文件
    	// ``````见2.1
    	
    	// step2: 读取MAT文件中保存的数据(double、matrix、cell、struct)
    	matvar_t* matvar_var = NULL;
    	matvar_var = Mat_VarRead(matfp, "test");		// 读取变量数值与信息
    	if (!matvar_var) {
    		printf("Error read MatVar: test!\n");
    		return -1;
    	}	
    
    	int iDataN = matvar_var->nbytes / matvar_var->data_size;	// 获取矩阵的大小
    	double* dI = (double*)malloc(iDataN * sizeof(double));		// 分配内存		// 不知道用法对不对hhh
    	memset(dI, 0, iDataN * sizeof(double));
    	if (matvar_var->data_type == MAT_T_DOUBLE) {				// 判断数据类型是否是double
    		const double* xData_I = (const double*)(matvar_var->data);	// 将data的值给xData_I
     		for (int i = 0; i < iDataN; ++i) {
     			printf("test[%d] = %lf\n", i, xData_I[i]);
    			/*
    			test[0]		test[3]		test[6]	
    			test[1]		test[4]		test[7]
    			test[2]		test[5]		test[8]
    			*/
     		}
    		memcpy(dI, xData_I, iDataN * sizeof(double));
    	}
    
    	// step3: 关闭MAT文件
    	Mat_VarFree(matvar_var);
    	Mat_Close(matfp);	
    }
    

    结构体matvar_t将包含以下信息:(具体说明可查看官方文档4.1节)

    name		| The name may be NULL, so the field should be checked prior to use.
    rank		| The minimum rank is 2.
    dims		| 
    class_type	| Indicates the class of variable(e.g. double-precision, structure, cell, etc)
    data_type	| Indicates the type of data stored in the data field of the MATLAB variable structure.
    isComplex	| 
    isLogical	| is non-zero of the variable should be interpreted as logical.
    isGlobal	| 
    

    4. 读取struct类型

    同2.3处声明:本人是菜鸡,代码随缘看= =

    读取struct类型数据(以读取xxx.mat文件中的test2结构体数组为例。test2结构体有两个元素,读取其中的data1(数组类型))

    void LoadStarData(void) {
    	// step1: 打开MAT文件
    	mat_t* matfp;
    	const char* file;		// MAT文件名
    	file = "xxx.mat";
    	const int column = 2;	// MAT文件对应的struct的元素数量。
    
    	matfp = Mat_Open(file, MAT_ACC_RDONLY);
    	if (NULL == matfp) {
    		printf("Error opening MAT file %s!\n", file);
    	}
    
    	// step2: 读取MAT文件中保存的数据(double、matrix、cell、struct)
    	matvar_t* structvar_patr = NULL, * data1 = NULL;							// 初始化保存数据的指针
    	structvar_patr = Mat_VarRead(matfp, "test2");
    	if (!structvar_patr) {
    		printf("Error read MatVar: test2!\n");
    	}
    	else if (structvar_patr->data_type == MAT_T_STRUCT) {						// 判断读取到的内容是否为结构体
    		const int list_length = structvar_patr->nbytes / structvar_patr->data_size / column;	// list_length*1 struct
    		for (i = 0; i < list_length; i++) {
    			data1 = Mat_VarGetStructFieldByName(structvar_patr, "data1", i);	// 以变量名读数据,也有其他读数据的模式。
    			if (data1 ) {
    				const double* xData_star = (const double*)(data1->data);
    				const int iDataN = data1->nbytes / data1->data_size;			// data1数组的长度
    				for (j = 0; j < iDataN; j++) {
    					A[i].B[j] = xData_star[j];									// 随缘
    				}
    			}
    		}
    	}
    
    	Mat_VarFree(data1);						// 释放空间,关闭文件
    	Mat_VarFree(structvar_patr);
    	Mat_Close(matfp);
    }
    

    总结

    没啥好说的。如上。

    展开全文
  • matlab图片批量预处理并保存为mat数据和jpg文件。~~预处理中的代码可以替换成其他方式,这里只是做个引导。批处理的文件夹以及图片的格式请根据实际情况自行调整。
  • Android和OpenCV的学习mat运算/颜色转换

    千次阅读 2022-04-17 19:49:55
    1.Mat 1.1 Mat的概念 Android中对图像是用bitmap格式来进行处理,而openCV中是采用Mat格式进行处理。所以我们在Android中使用OpenCV也要将Bitmp转化为Mlat格式。Mat类用于表示一个多维的单通道或者多通道的数组...
  • Mat数据格式

    千次阅读 2019-08-19 16:29:29
    目录1 图片格式转换2 png格式转换为Mat3 读写Mat格式的数据 1 图片格式转换 以下代码为Mat、QImage、QPixmap图片格式之间的转换函数: #include <opencv2/opencv.hpp> #include <opencv2/core/core.hpp...
  • bitmap与mat互转方便opencv操作

    万次阅读 2021-11-16 17:04:48
    亲测可用,达到的效果是在java层中输入bitmap,在c++层里将bitmap转为mat,然后用opencv来进行图像处理,最后将处理好的mat再转为bitmap给到java层。
  • ncnn Mat矩阵类

    千次阅读 2022-03-29 10:48:21
    ncnn-mat.h class NCNN_EXPORT Mat 构造函数 // empty Mat(); // vec Mat(int w, size_t elemsize = 4u, Allocator* allocator = 0); // image Mat(int w, int h, size_t elemsize = 4u, Allocator* allocator = 0);...
  • OpenCV中 Mat 的使用方法

    千次阅读 2022-04-03 18:59:26
    Mat 是 OpenCV 中的数据类型,储存矩阵形式的数据,构造 Mat 类型的方法有很多,都是通过 Mat 这个构造函数进行实现(Mat 也是构造 Mat 数据类型的函数)。 本文主要介绍 Mat 的构造方法和 Mat 类的访问以及相关的...
  • 2.cv::Mat初始化及其他类型转Mat

    千次阅读 2021-11-30 15:34:13
    Mat的构造函数 Mat () Mat (int rows, int cols, int type) Mat (Size size, int type) Mat (int rows, int cols, int type, const Scalar &s) Mat (Size size, int type, const Scalar &s) ...
  • 4、OpenCV中的Mat

    千次阅读 2021-01-06 15:36:28
    OpenCV 中的Mat类一、学习目标二、Mat 介绍(建议细读)三、Mat的存储方法四、显示地创建 Mat 对象五、格式化输出 Mat 对象六、其他常见元素的输出七、致谢 一、学习目标 我们有多种方法从现实世界中获取数字图像:...
  • opencv(mat与qimage 的互转)及图像处理一、opencv库文件二、使用方式(Qt)三、QImage 转 Mat (不太全,多多指教)四、Mat转 QImage总结 一、opencv库文件 编译好的opencv 库。 二、使用方式(Qt) 把上面下载的...
  • JVM系列之:MAT工具使用教程

    千次阅读 2022-03-31 21:30:15
    本文为《深入学习 JVM 系列》第二十三篇文章 Eclipse Memory Analyzer (MAT)是一个快速且功能丰富的Java堆...如果 JDK 版本为 11,且 MAT 版本是最新的,还需要修改 /Applications/mat.app/Contents/Eclipse/Memor.
  • OpenCV基础---图像存储器(Mat类)

    千次阅读 2021-09-12 08:44:43
    学习图像处理首先要学会如何操作矩阵信息,在OpenCV中提供了一个Mat类用于存储矩阵数据。 Mat类用来保存矩阵类型的数据信息,包括向量,矩阵,灰度或彩色图像等数据。Mat类分为矩阵头和指向存储数据的矩阵指针两...
  • OpenCV中Mat类的使用

    千次阅读 2021-02-26 04:17:57
    OpenCV的Mat类可以表示一个N维的数组,数组的每个位置可以是单通道或多通道。可以用来存储图片(灰度或彩色)、向量、直方图等很多东西。
  • OpenCV中的Mat

    千次阅读 2020-05-03 17:04:02
    OpenCV Mat类 OpenCV 自 2001 年出现以来。在那些日子里库是围绕C接口构建的。在那些日子里,他们使用名为IplImage C 的结构在内存中存储图像。 使用这个结构的问题是将 C 语言的所有负面效果都摆到了桌面上。最大的...
  • GLM 中的mat4

    千次阅读 2020-10-29 16:25:37
    GLM 中的mat4xxxxmat4中内存的排列方式mat4的使用方式glm::frustum四元数转mat4glm::translate xxxx mat4中内存的排列方式 mat4的类定义在type_mat4x4.hpp中,下面是对整个类代码的部分截取: struct tmat4x4 { ...
  • Opencv3 core模块解析之Mat类(1)

    千次阅读 2022-03-23 17:57:25
    在阅读opencv文档和源码时,常常看到InputArray、OutputArray、UMat、Mat_等“奇怪”的类,与我们常用的Mat,好像一样又不完全一样,这些其实主要在opencv内部用,其中有些文档都很少甚至没有,在opencv外部程序还是...
  • python将mat文件转为png

    千次阅读 2022-03-14 09:48:10
    花费了很大力气做这件事,总是出现各种错误,现在终于解决了 ...import mat73 # 数据矩阵转图片的函数 def MatrixToImage(data): data = data*255 new_im = Image.fromarray(data.astype(np.uint8)) re

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 348,963
精华内容 139,585
关键字:

mat

友情链接: ORB.rar