基于GDAL进行图像的读取, 保存, 滤波

基于GDAL进行图像的读取, 保存, 滤波

目前支持: 自定义算子的图像滤波, 图像读取,保存, 通道分离等功能

#pragma once

#ifdef __GDAL_UTILITY__
#include <gdal/gdal_priv.h>
#include <gdal/gdal.h>
#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
#include <algorithm>
#include <list>
#include <vector>
#include <array>
#include <cassert>
#include <memory>
#include <cstring>
#include <initializer_list>
#include <random>
#include <thread>


namespace GD {

	using namespace std;
	void init() {
		GDALAllRegister();
		CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "NO");
	}

	template<typename T>
	T sum(vector<T> const& v) {
		T sum = 0;
		std::for_each(v.begin(), v.end(), [&](T const& e) {sum += e; });
		return sum;
	}
	template<typename T>
	int partition(vector<T>& vec, int left, int right) {
		int i = left, j = right + 1;
		T pivot = vec[left];
		while (1) {
			while (vec[++i] < pivot) {
				if (i == right) break;
			}
			while (vec[--j] > pivot) {
				if (j == left) break;
			}
			if (i >= j) break;
			swap(vec[i], vec[j]);
		}
		swap(vec[left], vec[j]);
		return j;
	}

	template<typename T>
	T qSelect(vector<T>& vec, size_t k) {
		int low = 0, high = vec.size() - 1;
		while (low <= high) {
			int j = partition(vec, low, high);
			if (j == k) {
				return vec[k];
			}
			else if (j > k) {
				high = j - 1;
			}
			else if (j < k) {
				low = j + 1;
			}
		}
		return vec[k];
	}


	template<typename _Ty>
	struct Matrix {
	public:
		static_assert(std::is_arithmetic<_Ty>::value, "_Ty must be numeric type");
		// data
		vector<_Ty*> Data;
		size_t m_width, m_height;
	public:
		Matrix(size_t width = 1, size_t height = 1) :m_width(width), m_height(height) {
			Data = vector<_Ty*>(height, nullptr);
			for (int i = 0; i < height; ++i) {
				Data[i] = new _Ty[width];
				memset((void*)Data[i], 0, width * sizeof(_Ty));
			}
			int centerx = width / 2, centery = height / 2;
			Data[centerx][centery] = 1;
		}
		Matrix(std::initializer_list<std::initializer_list<_Ty>> const& init_list)
		{
			size_t listW = init_list.begin()->size(), listH = init_list.size();
			m_width = listW;
			m_height = listH;
			if (listW != m_width || listH != m_height) {
				cerr << "Matrix init error" << endl;
				exit(1);
			}
			int i = 0;
			Data = vector<_Ty*>(m_height);
			for (auto const& list : init_list) {
				if (list.size() != m_width) {
					cerr << "Matrix init error" << endl;
					exit(1);
				}
				int j = 0;
				Data[i] = new _Ty[m_width];
				memset((void*)Data[i], 0, m_width * sizeof(_Ty));
				for (auto e : list) {
					Data[i][j++] = e;
				}
				++i;
			}
		}
	};

	template<typename T>
	Matrix<T> AverageKernel(size_t size) {
		if ((size & 1) == 0) {
			std::cout << "size must be odd" << endl;
		}

		Matrix<T> res(size, size);
		for (int i = 0; i < size; ++i) {
			for (int j = 0; j < size; j++) {
				res.Data[i][j] = 1.0 / (size * size);
			}
		}
		return res;
	}


	template<typename T>
	Matrix<T> SobelKernelx() {
		return Matrix<T>(
			{ {-1., -2., -1.},
			  { 0.,  0.,  0.},
			  { 1.,  2.,  1.} });
	}

	template<typename T>
	Matrix<T> SobelKernely() {
		return Matrix<T>(
			{ {-1., 0.,  1.},
			  {-2., 0.,  2.},
			  {-1., 0.,  1.} });
	}
	/**
	* { {-1., -2., -1.},
		{ 0.,  0.,  0.},
		{ 1.,  2.,  1.} });

	  { {-1., 0.,  1.},
		{-2., 0.,  2.},
		{-1., 0.,  1.} });
	*/
	template<typename T>
	Matrix<T> LaplaceKernel_8() {
		return Matrix<T>(
			{ {1,  1, 1},
			  {1, -8, 1},
			  {1,  1, 1} }
		);
	}

	template<typename T>
	Matrix<T> LaplaceKernel_4() {
		return Matrix<T>(
			{ {0,  1, 0},
			  {1, -4, 1},
			  {0,  1, 0} }
		);
	}

	template<typename T>
	Matrix<T> LaplaceSharpening_4() {
		return Matrix<T>(
			{ {0,  1, 0},
			  {1, -5, 1},
			  {0,  1, 0} }
		);
	}

	template<typename T>
	Matrix<T> LaplaceSharpening_8() {
		return Matrix<T>(
			{ {1,  1, 1},
			  {1, -9, 1},
			  {1,  1, 1} }
		);
	}
	template<typename T>
	Matrix<T> GaussianKernel(size_t size, T stdX, T stdY) {
		// 得到size*size的高斯核
		Matrix<T> ret(size, size);
		T sum = 0;
		for (int i = 0; i < size; ++i) {
			T x = i - size / 2;
			for (int j = 0; j < size; ++j) {
				T y = j - size / 2;
				ret.Data[i][j] = exp(-(x * x / (2 * stdX * stdX) + y * y / (2 * stdY * stdY)));
				sum += ret.Data[i][j];
			}
		}
		for (int i = 0; i < size; ++i) {
			for (int j = 0; j < size; j++) {
				ret.Data[i][j] /= sum;
			}
		}
		return ret;
	}

	class RasterBase {
		void* pData;
	public:
		RasterBase() = default;
		RasterBase(const string& filepath) {}
		RasterBase(const char* filepath) {}

		virtual size_t width() const { return 0; }
		virtual size_t height() const { return 0; }
		virtual size_t bands() const { return 0; }
		virtual void* data() const { return nullptr; }
		virtual GDALDataType type() const { return GDT_Unknown; }
		virtual void init(GDALDataset* pDatasetRead,
			size_t lWidth, size_t lHeight, size_t nBands,
			GDALDataType datatype) {};
		virtual void save(string const&, string const& DriverName = "GTIFF")const {};
		virtual vector<array<size_t, 256>> histgram() const { return vector<array<size_t, 256>>(); }
		virtual RasterBase* equalizeHist(vector<array<size_t, 256>> histgram) { return nullptr; }
		virtual RasterBase* equalizeHist() { return nullptr; }
		virtual RasterBase* channel_extraction(size_t channel) { return nullptr; };
		virtual RasterBase* filter(Matrix<float> const& kernel) { return nullptr; }
		virtual RasterBase* filter(Matrix<double> const& kernel) { return nullptr; }
		virtual RasterBase* MedianFilter() { return nullptr; }
		virtual RasterBase* addSalt(size_t num) { return nullptr; }
		virtual RasterBase* Sobel() { return nullptr; }
		virtual RasterBase* Laplace_4() { return nullptr; }
		virtual RasterBase* Laplace_8() { return nullptr; }
		virtual RasterBase* GaussBlur(size_t size, double stdx, double stdy) { return nullptr; }
		virtual RasterBase* addGaussNoise(size_t size, float stdy) { return nullptr; }
		virtual RasterBase* Laplace_4_Sharpening() { return nullptr; }
		virtual RasterBase* Laplace_8_Sharpening() { return nullptr; }
		virtual RasterBase* Sobel_Sharpening() { return nullptr; }
		virtual RasterBase* toGray() { return nullptr; }
		virtual ~RasterBase() {};
	};

	template<typename _T>
	_T* Malloc(size_t width, size_t height, size_t bands) {
		return (_T*)CPLMalloc(width * height * bands * sizeof(_T));
	}

	using RasterPtr = std::shared_ptr<RasterBase>;

	template<typename T>
	class Raster : virtual public RasterBase {
	private:
		GDALDataset* pDatasetRead;
		GDALDriver* pDriver;
		size_t lWidth, lHeight, nBands;
		T* pData;
		GDALDataType datatype;
		template<typename _T>
		_T& at(size_t x, size_t y) {
			return pData[x * width * nBands + y];
		}

		template<typename _Ty>
		vector<_Ty> conv(long long pos, Matrix<_Ty> const& mat) {
			// 对单个像素进行卷积, i为图像中的位置, 原图像边界采用0填充
			vector<_Ty> res;
			size_t total = lHeight * lWidth;
			long long newpos = pos % total;
			size_t x = newpos % lWidth, y = newpos / lWidth;
			long long n = pos / total;
			size_t matw = mat.m_width, math = mat.m_height;
			long long matx = matw / 2, maty = math / 2;
			for (int j = -maty; j <= maty; ++j) {
				int yj = y + j;
				for (int i = -matx; i <= matx; ++i) {
					int xi = x + i;
					if (xi < 0 || xi >= lHeight || yj < 0 || yj >= lWidth) {
						res.push_back(0);
						continue;
					}
					long long index = yj * lWidth + xi + n * total;
					res.push_back(((_Ty)pData[index]) * ((_Ty)mat.Data[maty + j][matx + i]));
				}
			}
			return res;
		}

		template<typename _Ty>
		RasterBase* Laplace(Matrix<_Ty> const& kernel) {
			RasterPtr pLaplace{ filter(kernel) };
			RasterBase* ret{ new Raster<T>(lWidth, lHeight, 1, datatype) };
			size_t Area = lWidth * lHeight;
			for (size_t i = 0; i < Area; ++i) {
				double sum{ 0.0 };
				for (long long channel = 0; channel < nBands; ++channel) {
					long long index = i + channel * Area;
					sum += ((T*)pLaplace->data())[index];
				}
				sum /= 3;
				((T*)ret->data())[i] = (T)sum;
			}
			return ret;
		}

	public:
		size_t width() const override { return lWidth; }
		size_t height() const override { return lHeight; }
		size_t bands() const override { return nBands; }
		void* data() const override { return (void*)pData; }
		GDALDataType type() const override { return datatype; }
		void init(GDALDataset* pDatasetRead,
			size_t lWidth, size_t lHeight, size_t nBands,
			GDALDataType datatype)override
		{
			this->pDatasetRead = pDatasetRead;
			this->lWidth = lWidth; this->lHeight = lHeight; this->nBands = nBands;
			this->datatype = datatype;
			T* p(Malloc<T>(lWidth, lHeight, nBands));
			if (this->pDatasetRead)
				pDatasetRead->RasterIO(GF_Read, 0, 0, lWidth, lHeight, (void*)p, lWidth, lHeight, datatype, nBands, NULL, 0, 0, 0);//读取图像数据
			this->pData = p;
		}
		void save(string const& filepath, string const& DriverName = "GTIFF") const override {
			GDALDataset* pDatasetSave;
			auto pDriver = GetGDALDriverManager()->GetDriverByName(DriverName.c_str());
			pDatasetSave = pDriver->Create(filepath.c_str(), lWidth, lHeight, nBands, datatype,
				nullptr);
			assert(pDatasetSave != nullptr);
			pDatasetSave->RasterIO(GF_Write, 0, 0, lWidth, lHeight, (void*)pData, lWidth, lHeight, datatype, nBands, NULL, 0, 0, 0);//创建图像数据
			GDALClose(pDatasetSave);
		}

		vector<array<size_t, 256>> histgram() const override {
			vector<array<size_t, 256>> ret(nBands);
			for (int i = 0; i < nBands; ++i) {
				ret[i].fill(0);
			}
			long long total = this->lWidth * this->lHeight;
			for (int channel = 0; channel < nBands; ++channel) {
				auto p = pData + channel * total;
				for (int i = 0; i < total; ++i) {
					++ret[channel][p[i]];
				}
			}
			return ret;
		}

		RasterBase* equalizeHist(vector<array<size_t, 256>> histgram) override {
			RasterBase* ret{ new Raster<T> };
			ret->init(nullptr, lWidth, lHeight, nBands, datatype);
			size_t total = lHeight * lWidth;
			memcpy((T*)ret->data(), (T*)this->data(), nBands * total * sizeof(T));
			for (int channel = 0; channel < nBands; ++channel) {
				T* srcbegin = (T*)this->data() + lHeight * lWidth * channel;
				T* tarbegin = (T*)ret->data() + lHeight * lWidth * channel;
				for (int i = 1; i < 256; ++i) {
					histgram[channel][i] += histgram[channel][i - 1];
				}
				for (int i = 0; i < total; ++i) {
					tarbegin[i] = static_cast<T>(255.0 * histgram[channel][srcbegin[i]] / total);
				}
			}
			return ret;
		}

		RasterBase* equalizeHist()override {
			return equalizeHist(histgram());
		}

		RasterBase* channel_extraction(size_t channel) {
			assert(channel < nBands);
			RasterBase* ret{ new Raster<T> };
			ret->init(nullptr, lWidth, lHeight, nBands, datatype);
			size_t total = lHeight * lWidth;
			T* srcbegin = pData + lHeight * lWidth * channel;
			T* tarbegin = (T*)ret->data() + lHeight * lWidth * channel;
			memset(ret->data(), 0, total * sizeof(T));
			for (int i = 0; i < total; ++i) {
				tarbegin[i] = srcbegin[i];
			}
			return ret;
		}


		RasterBase* filter(Matrix<float> const& kernel) {
			if (kernel.m_width % 2 == 0 || kernel.m_height % 2 == 0) {
				cerr << "kernel size must be odd" << endl;
				exit(1);
			}
			RasterBase* ret{ new Raster<T>(lWidth, lHeight, nBands, datatype) };
			size_t total = lHeight * lWidth * nBands;
			for (size_t i = 0; i < total; ++i) {
				auto res = conv(i, kernel);
				double s = sum(res);
				if (s < 0) s = fabs(s);
				if (s > 255) s = 255;
				((T*)ret->data())[i] = (T)(s);
			}
			return ret;
		}

		RasterBase* filter(Matrix<double> const& kernel) {
			if (kernel.m_width % 2 == 0 || kernel.m_height % 2 == 0) {
				cerr << "kernel size must be odd" << endl;
				exit(1);
			}
			RasterBase* ret{ new Raster<T>(lWidth, lHeight, nBands, datatype) };
			size_t total = lHeight * lWidth * nBands;
			for (size_t i = 0; i < total; ++i) {
				auto res = conv(i, kernel);
				double s = sum(res);
				if (s < 0) s = fabs(s);
				if (s > 255) s = 255;
				((T*)ret->data())[i] = (T)(s);
			}
			return ret;
		}

		RasterBase* MedianFilter()override {
			RasterBase* ret{ new Raster<T>(lWidth, lHeight, nBands, datatype) };
			size_t total = lHeight * lWidth * nBands;
			Matrix<int> kernel{ {1, 1, 1} ,{1, 1, 1}, {1, 1, 1} };
			for (size_t i = 0; i < total; ++i) {
				auto res = conv(i, kernel);
				((T*)ret->data())[i] = qSelect(res, res.size() / 2);
			}
			return ret;
		}

		RasterBase* addSalt(size_t num) {
			size_t limit = lWidth * lHeight;
			RasterBase* ret{ new Raster<T>(lWidth, lHeight, nBands, datatype) };
			memcpy(ret->data(), this->data(), limit * nBands);
			for (long long i = 0; i < num; ++i) {
				int randomIndex = (rand() * rand()) % limit;
				bool is_white = rand() % 2;
				for (int channel = 0; channel < nBands; ++channel) {
					((T*)ret->data())[randomIndex + channel * limit] = is_white ? 255 : 0;
				}
			}
			return ret;
		}
		RasterBase* Sobel() {
			size_t total = lWidth * lHeight;
			RasterBase* ret{ new Raster<T>(lWidth, lHeight, 1, datatype) };
			RasterPtr Sobelx(filter(SobelKernelx<float>()));
			RasterPtr Sobely(filter(SobelKernely<float>()));
			for (long long i = 0; i < total; ++i) {
				double x{ .0 }, y{ .0 };
				for (int channel = 0; channel < nBands; ++channel) {
					x += ((T*)Sobelx->data())[i + channel * total];
					y += ((T*)Sobely->data())[i + channel * total];
				}
				double s = sqrt(x * x + y * y);
				if (s > 255) s = 255;
				((T*)ret->data())[i] = (T)s;
			}
			return ret;
		}

		RasterBase* GaussBlur(size_t size, double stdx, double stdy)override {
			return filter(GaussianKernel(size, stdx, stdy));
		}
		RasterBase* addGaussNoise(size_t size, float std) {
			size_t total = lHeight * lWidth * nBands;
			RasterBase* ret{ new Raster<T>(lWidth, lHeight, nBands, datatype) };
			memcpy(ret->data(), this->data(), total * sizeof(T));
			std::default_random_engine e;
			std::normal_distribution<float> x(0, std);
			for (long long i = 0; i < size; ++i) {
				int randomIndex = (rand() * rand()) % total;
				double s = ((T*)ret->data())[randomIndex] + x(e);
				if (s < 0) s = 0;
				if (s > 255) s = 255;
				((T*)ret->data())[randomIndex] = (T)(s);
			}
			return ret;
		}
		RasterBase* Laplace_4()override {
			return Laplace(LaplaceKernel_4<float>());
		}

		RasterBase* Laplace_8()override {
			return Laplace(LaplaceKernel_8<float>());
		}

		RasterBase* Laplace_4_Sharpening() {
			return filter(LaplaceSharpening_4<float>());
		}
		RasterBase* Laplace_8_Sharpening() {
			return filter(LaplaceSharpening_8<float>());
		}
		RasterBase* Sobel_Sharpening() {
			size_t total = lWidth * lHeight * nBands;
			RasterBase* ret{ new Raster<T>(lWidth, lHeight, nBands, datatype) };
			RasterPtr Sobelx(filter(SobelKernelx<float>()));
			RasterPtr Sobely(filter(SobelKernely<float>()));
			for (long long i = 0; i < total; ++i) {
				T x = ((T*)Sobelx->data())[i];
				T y = ((T*)Sobely->data())[i];
				double s = sqrt(x * x + y * y) + pData[i];
				if (s < 0) s = fabs(s);
				if (s > 255) s = 255;
				((T*)ret->data())[i] = (T)(s);
			}
			return ret;
		}

		RasterBase* toGray() override {
			RasterBase* ret{ new Raster<T>(lWidth, lHeight, 1, datatype) };
			size_t total = lWidth * lHeight;
			double weights[] = { 0.299, 0.587, 0.114 };
			for (size_t i = 0; i < total; ++i) {
				double sum{ 0.0 };
				for (long long channel = 0; channel < nBands; ++channel) {
					long long index = i + channel * total;
					sum += weights[channel] * ((T*)pData)[index];
				}
				((T*)ret->data())[i] = (T)sum;
			}
			return ret;
		}

	public:
		Raster() {
			pData = nullptr;
			this->lHeight = -1;
			this->lHeight = -1;
			pDatasetRead = nullptr;
			pDriver = nullptr;
		}
		Raster(const string& filepath) :Raster(filepath.c_str()) {};
		Raster(const char* filepath) {
			assert(filepath != nullptr);
		}

		Raster(size_t width, size_t height, size_t nBands, GDALDataType datatype) {
			init(nullptr, width, height, nBands, datatype);
		}

		~Raster() {
			if (pDatasetRead)
				GDALClose(pDatasetRead);//关闭数据集
			if (pData)
				delete[] pData;
		}
	};

	RasterBase* getByType(GDALDataType datatype) {
		RasterBase* ret = nullptr;
		switch (datatype) {
		case GDT_Byte:
			ret = new Raster<unsigned char>();
			break;
		case GDT_UInt16:
			ret = new Raster<unsigned short>();
			break;
		case GDT_Int16:
			ret = new Raster<short>();
			break;
		case GDT_UInt32:
			ret = new Raster<unsigned int>();
			break;
		case GDT_Int32:
			ret = new Raster<int>();
			break;
		case GDT_Float32:
			ret = new Raster<float>();
			break;
		case GDT_Float64:
			ret = new Raster<double>();
			break;
		}
		assert(ret != nullptr);
		return ret;
	}

	RasterBase* open(const string& filepath) {
		GDALDataset* pDatasetRead{ nullptr };
		size_t lWidth{ 0 }, lHeight{ 0 }, nBands{ 0 };
		GDALDataType datatype{ GDT_Unknown };
		try {
			pDatasetRead = (GDALDataset*)GDALOpen(filepath.c_str(), GA_ReadOnly);
			lWidth = pDatasetRead->GetRasterXSize();//获取图像宽度
			lHeight = pDatasetRead->GetRasterYSize();//获取图像高度
			nBands = pDatasetRead->GetRasterCount();//获取图像波段数
			datatype = pDatasetRead->GetRasterBand(1)->GetRasterDataType();//获取图像格式类型
		}
		catch (std::exception& e) {
			cerr << e.what() << endl;
			exit(1);
		}
		RasterBase* ptr(getByType(datatype));
		ptr->init(pDatasetRead, lWidth, lHeight, nBands, datatype);
		return ptr;
	}


	RasterBase* operator-(RasterBase const& lhs, RasterBase const& rhs) {
		assert(lhs.width() == rhs.width() && lhs.height() == rhs.height() && lhs.bands() == rhs.bands());
		RasterBase* ret{ new Raster<unsigned char>(lhs.width(), lhs.height(), lhs.bands(), lhs.type()) };
		size_t total = lhs.width() * lhs.height() * lhs.bands();
		for (size_t i = 0; i < total; ++i) {
			double diff = ((unsigned char*)lhs.data())[i] - ((unsigned char*)rhs.data())[i];
			if (diff < 0) diff = 0;
			((unsigned char*)ret->data())[i] = (unsigned char)diff;
		}
		return ret;
	}
}
#endif // __GDAL__UTILITY__H__
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
GDAL是一个开源的地理数据处理库,它提供了许多用于处理栅格数据(如.tif格式的图像)的工具和函数。其中,滤波是一种常用的栅格数据处理操作。 GDAL支持多种滤波算法,如均值滤波、高斯滤波、中值滤波等。这些滤波算法可以通过GDAL中的卷积函数进行实现。以下是使用GDAL对tif影像进行高斯滤波的示例代码: ```python from osgeo import gdal from osgeo import gdal_array from osgeo import osr import numpy as np # 打开tif影像 ds = gdal.Open('input.tif') # 获取影像的宽度和高度 width = ds.RasterXSize height = ds.RasterYSize # 读取影像数据 band = ds.GetRasterBand(1) data = band.ReadAsArray(0, 0, width, height) # 定义高斯滤波核 sigma = 3.0 size = int(sigma * 3) * 2 + 1 kernel = np.zeros((size, size)) for i in range(size): for j in range(size): x = i - size // 2 y = j - size // 2 kernel[i, j] = np.exp(-(x**2 + y**2) / (2 * sigma**2)) # 归一化滤波核 kernel /= kernel.sum() # 对影像数据进行滤波 filtered_data = gdal_array.convolve(data, kernel) # 创建输出tif影像 driver = gdal.GetDriverByName('GTiff') out_ds = driver.Create('output.tif', width, height, 1, band.DataType) # 将滤波后的数据写入输出影像 out_band = out_ds.GetRasterBand(1) out_band.WriteArray(filtered_data) # 设置投影信息和仿射变换参数 out_ds.SetGeoTransform(ds.GetGeoTransform()) out_ds.SetProjection(ds.GetProjection()) # 释放资源 del ds del out_ds ``` 上述代码读取了一个tif影像的数据,然后利用高斯滤波核对数据进行滤波,并将结果保存到了另外一个tif影像中。其中,滤波核的大小和sigma值可以根据实际情况进行调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值