C++ OpenCV one-dimensional array to image?

I used GDAL to read the original image and then converted it into a one-dimensional array, but there was an error when I used OpencV to convert the one-dimensional array into an image, which was always displayed as a 3-channel gray image (the original image became nine small images pieced together), as shown in the following picture.
val_0

Here is a small example of the code,thank you.

	string strBigRasterFile = CPLFormFilename(big_raster_dir.c_str(), big_raster_name.c_str(), nullptr);
	GDALDataset* poRasterDS = (GDALDataset*)GDALOpen(strBigRasterFile.c_str(), GA_Update);
	if (poRasterDS == nullptr)
	{
		GDALClose((GDALDatasetH)poRasterDS);
		return false;
	}
	GDALDataType gdal_datatype = poRasterDS->GetRasterBand(1)->GetRasterDataType();

	int nBigXSize = poRasterDS->GetRasterXSize();
	int nBigYSize = poRasterDS->GetRasterYSize();
	int nBigBand  = poRasterDS->GetRasterCount();
	float* pBigImg = new float[nBigXSize * nBigYSize * nBigBand]();
	poRasterDS->RasterIO(GF_Read, 0, 0, nBigXSize, nBigYSize, pBigImg, nBigXSize, nBigYSize, gdal_datatype, nBigBand,
	    nullptr, 0, 0, 0, nullptr);

        //  convert the one-dimensional array into an image,
	cv::Mat imgBig(nBigYSize, nBigXSize, CV_8UC3, pBigImg);

	string bigImgFilename = out_dir + "/" + str_path + "_" + ".png";
	cv::imwrite(bigImgFilename, imgBig);

hypothesis: planar RGB data is written into pBigImg.

I could speculate further at this point but I’d rather you have the light bulb moment than be told the solution.

be aware of the layout of the data you get from GDAL, and the layout that OpenCV wants. they don’t match in at least two aspects.

you uploaded a jpeg, which means it’s lossy, but does either of this look familiar? I’m guessing the second one.

image image

you will need to change three parameters of your RasterIO call, and use cvtColor or change one more parameter of the RasterIO call

1 Like

Sorry for my late reply.
Thank you for your point, the correct picture is indeed the second picture as you said.
I solved this problem because the three-band data read by GDAL cannot be directly converted to Mat, but it needs to be read one band by one band. The complete code is as follows:

cv::Mat gdalToMat(GDALDataset* poRasterDS, int patchSizeX, int patchSizeY, int patchULX, int patchULY)
{
	std::vector<cv::Mat> imgMat;
	GByte* pafscan = new GByte[patchSizeX * patchSizeY];
	int nBand = poRasterDS->GetRasterCount();
	for (int band = 0; band < nBand; band++)
	{
		GDALRasterBand* pBand = poRasterDS->GetRasterBand(band + 1);
		pBand->RasterIO(GF_Read, patchULX, patchULY, patchSizeX, patchSizeY, pafscan, patchSizeX, patchSizeY, GDT_Byte, 0, 0);
		cv::Mat img = cv::Mat(patchSizeY, patchSizeX, CV_8UC1, pafscan);
		imgMat.push_back(img.clone());
		//delete[] pBand;
		img.release();
	}
	delete[] pafscan;
	pafscan = NULL;

	cv::Mat imgPatch;
	imgPatch.create(patchSizeY, patchSizeX, CV_8UC(nBand));
	merge(imgMat, imgPatch);
	imgMat.clear();

	cv::Mat imgPatchRGB;
	cv::cvtColor(imgPatch, imgPatchRGB, cv::COLOR_BGR2RGB);

	return imgPatchRGB;
}