选择性直方图均衡(仅在图像的指定区域)

Selective histogram equalization (only on a specified area of the image)

本文关键字:区域 图像 直方图 选择性      更新时间:2023-10-16

我正在qt创建者上发展,

我必须开发一个程序,该程序执行图像的直方图均衡。我的图像是16位灰度图像,因此我无法使用"均衡史"的OpenCV函数,因为它仅适用于8位灰度图像。

我写的代码执行以下内容:

void equalizeHist_16U(Mat* img)
{
    long hist[65535] = {0};
    double ratio;
    int i, j;
    assert(img->channels() == 1);
    assert(img->type() == CV_16U);
    ratio = 65535.0 / (img->cols*img->rows);
    //Cumulative histogram calculation
    compute_hist_16U(img, hist, true);
    for(i=0 ; i<img->cols ; i++)
    {
        for(j=0 ; j<img->rows ; j++)
        {
            img->at<unsigned short>(j,i) = ratio*hist[img->at<unsigned short>(j,i)];
        }
    }
}
long compute_hist_16U (Mat* img, long* hist, bool cumul)
{
    unsigned short i, j, k;
    long* b;
    long max = 0;
    //is the image 16bits grayscale ?
    assert(img->channels() == 1);
    assert(CV_16U == img->type());
    //histogram calculation
    for(i=0 ; i<img->cols ; i++)
    {
        for(j=0 ; j<img->rows ; j++)
        {
            hist[img->at<unsigned short>(j,i)]++;
            if(hist[img->at<unsigned short>(j,i)] > max)
                max = hist[img->at<unsigned short>(j,i)];
        }
    }
    //Cumulative histogram calculation (if cumul=true)
    if(cumul)
    {
        for(b=hist ; b<hist+65535 ; b++)
        {
            *(b+1) += *b;
        }
    }
    return (cumul ? hist[65535] : max);
}

它可以按照我的期望,现在我想对图像的直方图平衡,而仅在图像的指定部分上进行。我在功能中添加了x1,x2,y1,y2参数,并更改了我的" for"的界限(我更改的代码行具有箭头):

---->void equalizeHist_16U(Mat* img, int x1, int x2, int y1, int y2)
{
    long hist[65535] = {0};
    double ratio;
    int i, j;
    assert(img->channels() == 1);
    assert(img->type() == CV_16U);
    ratio = 65535.0 / (img->cols*img->rows);
    //Cumulative histogram calculation
    compute_hist_16U(img, hist, true);
    ---->for(i=x1 ; i<=x2 ; i++)
    {
        ---->for(j=y1 ; j<=y2 ; j++)
        {
            img->at<unsigned short>(j,i) = ratio*hist[img->at<unsigned short>(j,i)];
        }
    }
}
---->long compute_hist_16U (Mat* img, long* hist, bool cumul, int x1, int x2, int y1, int y2)
{
    unsigned short i, j, k;
    long* b;
    long max = 0;
    //is the image 16bits grayscale ?
    assert(img->channels() == 1);
    assert(CV_16U == img->type());
    //histogram calculation
    ---->for(i=x1 ; i<=x2  ; i++)
    {
        ---->for(j=y1 ; j<=y2 ; j++)
        {
            hist[img->at<unsigned short>(j,i)]++;
            if(hist[img->at<unsigned short>(j,i)] > max)
                max = hist[img->at<unsigned short>(j,i)];
        }
    }
    //Cumulative histogram calculation (if cumul=true)
    if(cumul)
    {
        for(b=hist ; b<hist+65535 ; b++)
        {
            *(b+1) += *b;
        }
    }
    return (cumul ? hist[65535] : max);
}

但它无法正常工作,我的图像没有均衡,我的图像上没有极端的值(透明白色和深色黑色)。如果我尝试

equalizeHist_16U(&img, 0, 50, 0, 50)

我得到的图像非常非常明亮如果我尝试

equalizeHist(&img, 300, 319, 220, 239)

我得到的图像非常深

我认为我在循环范围上犯了一个错误,但找不到在哪里!也许你有一个主意?

预先感谢您

初步:
您是否注意到您没有在第二版的累积直方图功能上使用?

void equalizeHist_16U(Mat* img, int x1, int x2, int y1, int y2)

正在调用

compute_hist_16U(img, hist, true);

而不是:

long compute_hist_16U (Mat* img, long* hist, bool cumul, int x1, int x2, int y1, int y2)

(我想您想发布最后一个,否则我不会明白您为什么发布代码:))


实际答案:

如果您使用cv::Mat ROI,通过operator ()

,一切都会变得容易得多。

您的功能将如下:

void equalizeHist_16U(Mat* img, int x1, int x2, int y1, int y2) {
   //Here you should check you have x2 > x1 and y2 > y1 and y1,x1 >0 and x2 <= img->width and y2 <= img->height
   cv::Rect roi(x1,y1,x2-x1,y2-y1); 
   //To reproduce exactly the behaviour you seem to target,
   //it should be x2-x2+1 and y2-y1+1. 
   //But you should get used on the fact that extremes are,
   //as a convention, excluded
   cv::Mat& temp = *img; //Otherwise using operator() is complicated
   cv::Mat roiMat = temp(roi); //This doesn't do any memory copy, just creates a new header!
   void equalizeHist_16U(&roiMat); //Your original function!!
}

就是这样!如果这不起作用,则意味着您的原始功能该处理整个图像具有您以前看不到的错误。

当我有一些时间时,我将发布一些建议以使您的功能更快(例如,您应该避免使用.at,应在直方图计算结束时计算直方图中的最大值,您应该创建一个查找short的查找表,其中您将直方图乘以乘比率,以便应用直方图变得更快;而不是导致浮点转换的ratio变量,您可以简单地将直方图元素除以常数(img->width*img->height))和更整洁的(您应该通过参考来传递Mat,而不是使用指针,那是C风格,而不是C )

此外:

  • 为什么您从compute_hist_16U返回值?
  • long hist[65535]应该long hist[65536],以便索引65535有效。首先,65535是图像中的白色值。此外,当您使用b=hist+65534(最后一个周期)的b+1时,您可以在周期中使用它

    for(b=hist ; b<hist+65535 ; b++)
    {
        *(b+1) += *b;
    }
    

感谢您的回答。

初步我想我在粘贴代码时犯了一个错误,我忘了更改您注意到的行,这一行应该是您写的最后一行。

实际答案您的技术效果很好,无论选定区域如何,我的像素(透明白色和深色黑色)确实具有极端值。唯一的问题(我没有在问题中提及它,所以您不知道)是它只能保留所选区域,其余图像没有变化。实际上,我想对图像的指定部分进行直方图计算,并将该直方图应用于我的所有图像。

我还从compute_hist_16U删除了返回的值,并将long hist[65535]更改为long hist[65536]我更改了传递图像的方式,并删除了变量ratio。我使用了.at,因为它是访问文档中描述的像素值的方法,当我搜索"如何加入Pixel value OpenCV Mat"中所述的像素值"。而且我从未看过如何创建查找表

我的新功能是:

void compute_hist_16U (Mat &img, long* hist)
{
    unsigned short i, j;
    long* b;
    assert(img.channels() == 1);
    assert(CV_16U == img.type());
    for(i=0 ; i<=img.cols-1  ; i++)
    {
        for(j=0 ; j<=img.rows-1 ; j++)
        {
            hist[img.at<unsigned short>(j,i)]++;
        }
    }
    //Calcul de l'histogramme cumulé
    for(b=hist ; b<hist+65535 ; b++)
    {
        *(b+1) += *b;
    }
}
void equalizeHist_16U(Mat &img, int x1, int x2, int y1, int y2)
{
    long hist[65536] = {0};
    double ratio;
    int i,j;
    assert(img.channels() == 1);
    assert(img.type() == CV_16U);
    assert(x1>=0 && y1>=0 && x2>x1 && y2>y1);
    assert(y2<img.rows && x2<img.cols);
   cv::Rect roi(x1,y1,x2-x1+1,y2-y1+1);
   cv::Mat& temp = img;
   cv::Mat roiMat = temp(roi);
   compute_hist_16U(roiMat, hist);
   for(i=0 ; i<=img.cols-1 ; i++)
   {
       for(j=0 ; j<=img.rows-1 ; j++)
       {
           img.at<unsigned short>(j,i) = 65536.0*hist[img.at<unsigned short>(j,i)] / (roiMat.cols*roiMat.rows);
       }
   }
}
void equalizeHist_16U(Mat &img)
{
    equalizeHist_16U(img, 0, img.cols-1, 0, img.rows-1);
}

我认为它有效,如果我选择了图像的明亮部分,那么我在这部分(明亮的白色和深色黑色)上有极端值,其余图像非常黑。例如,如果我在右侧选择建筑物:http://www.noelshack.com/2015-20-1431349774-Result-ok.png

但是有时结果很奇怪,例如,如果我选择最黑的云:http://www.noelshack.com/2015-20-20-1431349774-Result-nok.png