opencv切片的矢量垫

时间:2018-01-31 15:58:32

标签: c++ opencv vector

我是 OpenCV 的新手。我正在使用 Visual Studio 2017 并使用插件 Image Watch 查看openCV的Mat文件。

我做了什么:

我必须读取一个二进制文件,以在double数组中获得1000个图像(256 * 320像素uint16,因此2个像素)。在此之后,我想用Image Watch查看我的数据以确保一切正常。所以我将第一个图像转换为8位的uchar来可视化它。我添加了我的代码(大部分内容都没有读过,只是到最后):

#include "stdafx.h"
#include <iostream>
#include "stdio.h"
#include <fstream>
#include <stdint.h>
#include "windows.h"
#include <opencv2/core/core.hpp>           // cv::Mat
#include <math.h>
#include <vector>

using namespace std;
using namespace cv;

template<class T>
T my_ntoh_little(unsigned char* buf) {
    const auto s = sizeof(T);
    T value = 0;
    for (unsigned i = 0; i < s; i++)
        value |= buf[i] << CHAR_BIT * i;
    return value;
}

int main()
{
    ifstream is("Filename", ifstream::binary);
    if (is) {
        // Reading size of the file and initialising variables
        is.seekg(0, is.end);
        int length = is.tellg();
        int main_header_size = 3000;
        int frame_header_size = 1000;
        int width = 320, height = 256, count_frames = 1000;
        int buffer_image = width * height * 2;
        unsigned char *data_char = new unsigned char[length]; // Variable which will contains all the data

        // Initializing 3D array for stocking all images
        double ***data;
        data = new double**[count_frames];
        for (unsigned i = 0; i < count_frames; i++) {
            data[i] = new double*[height];
            for (unsigned j = 0; j < height; j++)
                data[i][j] = new double[width];
        }

        // Reading the file once
        is.seekg(0, is.beg);
        is.read(reinterpret_cast<char*>(data_char), length);

        // Convert pixel by pixel uchar into uint16 (using pointer on data_char)
        int indice, minid = 65536.0, maxid = 0.0;
        for (unsigned count = 0; count < count_frames; count++) {
            // Initialize pointer address
            indice = main_header_size + count * (frame_header_size + buffer_image) + frame_header_size;

            for (unsigned i = 0; i < height; i++) {
                for (unsigned j = 0; j < width; j++) {
                    data[count][i][j] = my_ntoh_little<uint16_t>(data_char + indice);

                    // Search for min/max for normalize after
                    if (data[count][i][j] < minid and count == 0)
                        minid = data[count][i][j];
                    if (data[count][i][j] > maxid and count == 0)
                        maxid = data[count][i][j];

                    // Updating pointer to next pixel
                    indice += 2;
                }
            }
        }

        // Get back first image, normalize between 0-255, cast into uchar to the future Mat object
        uchar *dataImRGB = new uchar[width * height * 3];
        int image_display = 900;
        int pixel_norm;
        for (unsigned i = 0; i < height; i++) {
            for (unsigned j = 0; j < width; j++) {
                pixel_norm = round((data[image_display][i][j] - double(minid)) / double(maxid - minid) * 255);
                dataImRGB[i * 320 * 3 + 3 * j] = static_cast<uchar>(pixel_norm);
                dataImRGB[i * 320 * 3 + 3 * j + 1] = static_cast<uchar>(pixel_norm);
                dataImRGB[i * 320 * 3 + 3 * j + 2] = static_cast<uchar>(pixel_norm);
            }
        }

        // Create Mat object (it is imageRGB8 I can see on Image watch)
        Mat imageRGB8 = Mat(width, height, CV_8UC3, dataImRGB);

        // Creating a list of Map and add first Mat
        vector<Mat> listImages;
        listImages.push_back(imageRGB8);

        // -----------------------------------------------------------------------------------------
        // -----------------------------------------------------------------------------------------
        // Future : directly keep the uchar read in the original file and import it on a Mat object
        // But how to get the pixel at (0,0) of the first Mat on the vector ?
        // -----------------------------------------------------------------------------------------
        // -----------------------------------------------------------------------------------------

        // De-Allocate memory to prevent memory leak
        for (int i = 0; i < count_frames; ++i) {
            for (int j = 0; j < height; ++j)
                delete[] data[i][j];

            delete[] data[i];
        }
        delete[] data;
    }
    return 0;
}

我被困的地方:

我不知道如何使用此向量,如何操作数据。例如,如果我想做所有图像的平均值,那么向量中所有Mat对象的平均值,该怎么做?或者只是如何获得向量中第三个图像的第一个像素?这些例子的目的是向我解释使用这种类型的数据进行切片,因为我知道它如何与double的vector一起使用,而不是openCv对象。

提前感谢您提供任何帮助/建议。

1 个答案:

答案 0 :(得分:1)

假设您已将所有图像正确打包到图像列表中,则可以执行以下操作:

这将获得列表中所有图像的平均值:

cv::Scalar meansum(0.0f,0.0f,0.0f);
size_t length = listImages.size();
for (size_t i = 0; i < length; i++){
  //mu == mean of current image
  cv::Scalar mu = cv::mean(listImages[i]);
  meansum += mu;
}

float means[3] = { meansum[0] / length, meansum[1] / length, meansum[2] / length };
  std::cout << "Means " << means[0] << " " << means[1] << " " << means[2] << std::endl;

要获取第三个图像中的第一个像素,可以使用at()方法或行指针。 (行指针更快,但没有任何防止访问超出边界内存位置的保护。)

Mat third_image = list_images[2];
//using at()
uchar first_pixel_blue_value = third_image.at<uchar>(0,0,0);
std::cout<<(int)first_pixel_blue_value<<std::endl;

//using row pointer
uchar* row = third_image.ptr<uchar>(0); //pointer to row 0
std::cout<<"blue: "  <<(int)row[0];
std::cout<<" green: "<<(int)row[1];
std::cout<<" red: "  <<(int)row[2];

可在此处找到更多信息:

https://docs.opencv.org/3.1.0/d2/de8/group__core__array.html(在函数下)

在这里:

https://docs.opencv.org/trunk/d3/d63/classcv_1_1Mat.html