gpt4 book ai didi

c++ - cv::Mat 序列的逐像素中值

转载 作者:可可西里 更新时间:2023-11-01 18:29:11 26 4
gpt4 key购买 nike

注意:我不是在问中值滤波器。

我有一系列图像让我们说:

std::array<cv::Mat,N> sequence;

我想将所有这些图像融合在一起。这一张图片应该满足:

新图像的每个像素都是序列中相应像素的中值。换句话说:

Result(i,j)=median(sequence[0](i,j), sequence[1](i,j), ..., sequence[N](i,j));

是否有内置函数可以做到这一点?最快的方法是什么?

到目前为止,我的尝试是:遍历所有序列中的每个像素并排序,然后取中位数,然后将其存储在结果中。然而,这太过分了。

最佳答案

您可以使用直方图计算每个位置的连续中位数。

假设您使用的是 Mat1b 图像,每个直方图将有 256 个值。您需要存储直方图,以及所有 bin 的总和:

struct Hist {
vector<short> h;
int count;
Hist() : h(256, 0), count(0) {};
};

中值是直方图中对应于像素 count/2 一半的索引。来自 Rosetta Code 的片段:

int i;
int n = hist.count / 2; // 'hist' is the Hist struct at a given pixel location
for (i = 0; i < 256 && ((n -= hist.h[i]) >= 0); ++i);
// 'i' is the median value

当您添加或删除图像时,您会更新每个像素位置的直方图,并重新计算中值。此操作非常快,因为您不需要排序。

这样做有一些缺点:

  1. 这仅适用于 uchar 值,否则每个直方图的长度会太大
  2. 此方法将使用大量 RAM,因为它需要 行 x 列 直方图。它可能不适用于大图像。
  3. 以下实现适用于单 channel 图像,但可以轻松扩展到 3 channel 。
  4. 您可以使用基于两个堆的方法或近似方法。您可以在此处找到详细信息:

代码:

#include <vector>
#include <opencv2/opencv.hpp>

using namespace std;
using namespace cv;

struct Hist {
vector<short> h;
int count;
Hist() : h(256, 0), count(0) {};
};

void addImage(vector<Mat1b>& images, Mat1b& img, vector<vector<Hist>>& M, Mat1b& med)
{
assert(img.rows == med.rows);
assert(img.cols == med.cols);

for (int r = 0; r < img.rows; ++r) {
for (int c = 0; c < img.cols; ++c){

// Add pixel to histogram
Hist& hist = M[r][c];
++hist.h[img(r, c)];
++hist.count;

// Compute median
int i;
int n = hist.count / 2;
for (i = 0; i < 256 && ((n -= hist.h[i]) >= 0); ++i);

// 'i' is the median value
med(r,c) = uchar(i);
}
}

// Add image to my list
images.push_back(img.clone());
}

void remImage(vector<Mat1b>& images, int idx, vector<vector<Hist>>& M, Mat1b& med)
{
assert(idx >= 0 && idx < images.size());

Mat1b& img = images[idx];
for (int r = 0; r < img.rows; ++r) {
for (int c = 0; c < img.cols; ++c){

// Remove pixel from histogram
Hist& hist = M[r][c];
--hist.h[img(r, c)];
--hist.count;

// Compute median
int i;
int n = hist.count / 2;
for (i = 0; i < 256 && ((n -= hist.h[i]) >= 0); ++i);

// 'i' is the median value
med(r, c) = uchar(i);
}
}

// Remove image from list
images.erase(images.begin() + idx);
}

void init(vector<vector<Hist>>& M, Mat1b& med, int rows, int cols)
{
med = Mat1b(rows, cols, uchar(0));
M.resize(rows);
for (int i = 0; i < rows; ++i) {
M[i].resize(cols);
}
}


int main()
{
// Your images... be sure that they have the same size
Mat1b img0 = imread("path_to_image", IMREAD_GRAYSCALE);
Mat1b img1 = imread("path_to_image", IMREAD_GRAYSCALE);
Mat1b img2 = imread("path_to_image", IMREAD_GRAYSCALE);
resize(img0, img0, Size(800, 600));
resize(img1, img1, Size(800, 600));
resize(img2, img2, Size(800, 600));



int rows = img0.rows;
int cols = img0.cols;

vector<Mat1b> images; // All your images, needed only if you need to remove an image
vector<vector<Hist>> M; // histograms
Mat1b med; // median image

// Init data strutctures
init(M, med, rows, cols);

// Add images. 'med' will be the median image and will be updated each time
addImage(images, img0, M, med);
addImage(images, img1, M, med);
addImage(images, img2, M, med);

// You can also remove an image from the median computation
remImage(images, 2, M, med);

// Hey, same median as img0 and img1 ;D

return 0;
}

关于c++ - cv::Mat 序列的逐像素中值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38910945/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com