图像增强:多尺度的图像细节提升(multi-scale detail boosting)实现方法
#include <iostream>
#include <opencv2\opencv.hpp>
#include <opencv2\highgui\highgui.hpp>
using namespace std;
using namespace cv;
cv::Mat multiScaleSharpen(cv::Mat Src, int Radius)
{
int rows = Src.rows;
int cols = Src.cols;
int cha = Src.channels();
cv::Mat B1, B2, B3;
GaussianBlur(Src, B1, Size(Radius, Radius), 1.0, 1.0);//高斯模糊
GaussianBlur(Src, B2, Size(Radius*2-1, Radius*2-1), 2.0, 2.0);
GaussianBlur(Src, B3, Size(Radius*4-1, Radius*4-1), 4.0, 4.0);
double w1 = 0.5;
double w2 = 0.5;
double w3 = 0.25;
cv::Mat dest = cv::Mat::zeros(Src.size(), Src.type());
for (size_t i = 0; i < rows; i++)
{
uchar* src_ptr = Src.ptr<uchar>(i);
uchar* dest_ptr = dest.ptr<uchar>(i);
uchar* B1_ptr = B1.ptr<uchar>(i);
uchar* B2_ptr = B2.ptr<uchar>(i);
uchar* B3_ptr = B3.ptr<uchar>(i);
for (size_t j = 0; j < cols; j++)
{
for (size_t c = 0; c < cha; c++)
{
int D1 = src_ptr[3*j+c] - B1_ptr[3 * j + c];
int D2 = B1_ptr[3 * j + c] - B2_ptr[3 * j + c];
int D3 = B2_ptr[3 * j + c] - B3_ptr[3 * j + c];
int sign = (D1 > 0) ? 1 : -1;
dest_ptr[3 * j + c] = saturate_cast<uchar>((1 - w1*sign)*D1 - w2*D2 + w3*D3 + src_ptr[3 * j + c]);
}
}
}
return dest;
}
int main(int argc)
{
Mat src = imread("image\\test.jpg");
cv::imshow("src", src);
cvWaitKey(100);
cv::Mat dest=multiScaleSharpen(src,5);
cv::imshow("dest", dest);
cvWaitKey(0);
return 0;
}
作为一种简单可行的方法,是有效果的。并入GOCvHelper库中,并且向OpenCV进行推送。
为了进行pr的资料准备,需要做以下研究:
1、算法原理,比较能够将清楚的地方;(OK继续)
2、此类代码放在哪里比较合适,并且确保编译正确;
3、完善文档,提炼价值。
该算法来自论文
DARK IMAGE ENHANCEMENT BASED ON PAIRWISE TARGET CONTRAST AND MULTI-SCALE DETAIL BOOSTING
https://ieeexplore.ieee.org/abstract/document/7351031/
的第2.3节
论文的核心思想类似于Retinex,使用了三个尺度的高斯模糊,再和原图做减法,获得不同程度的细节信息,然后通过一定的组合方式把这些细节信息融合到原图中,从而得到加强原图信息的能力。值得一提的就是对D1的系数做了特殊的处理,算法的编码简单、效果明显。
对应的python实现
# -*- coding: utf-8 -*-
import cv2
import numpy as np
from numpy import uint8
from numpy import float32
from numpy import hstack
def multiScaleSharpen(img ,radius):
h,w,chan = img.shape
GaussBlue1 = np.zeros(img.shape,dtype = uint8)
GaussBlue2 = np.zeros(img.shape, dtype=uint8)
GaussBlue3 = np.zeros(img.shape, dtype=uint8)
Dest_float_img = np.zeros(img.shape, dtype=float32)
Dest_img = np.zeros(img.shape, dtype=uint8)
w1 = 0.5
w2 = 0.5
w3 = 0.25
GaussBlue1 = cv2.GaussianBlur(img,(radius,radius),1)
GaussBlue2 = cv2.GaussianBlur(img,(radius*2-1,radius*2-1),2)
GaussBlue3 = cv2.GaussianBlur(img,(radius*4-1,radius*4-1),4)
for i in range(0,h):
for j in range(0,w):
for k in range(0,chan):
Src = img.item(i,j,k)
D1 = Src-GaussBlue1.item(i,j,k)
D2 = GaussBlue1.item(i,j,k) - GaussBlue2.item(i,j,k)
D3 = GaussBlue2.item(i,j,k) - GaussBlue3.item(i,j,k)
if(D1 > 0):
sig = 1
else:
sig = -1
Dest_float_img.itemset((i,j,k),(1-w1*sig)*D1+w2*D2+w3*D3+Src)
Dest_img = cv2.convertScaleAbs(Dest_float_img)
return Dest_img
if __name__ == '__main__':
img = cv2.imread("175_result.bmp")
#img = cv2.imread("128.jpg")
multiScaleSharpen_out = np.zeros(img.shape, dtype=uint8)
multiScaleSharpen_out = multiScaleSharpen(img,5)#jishu
cv2.imwrite("multiScaleSharpen_175_result.bmp", multiScaleSharpen_out)
OpenCV自己是否有Shappen的东西?值得研究。
#include "opencv2/core/utility.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include <stdio.h>
using namespace cv;
using namespace std;
int sharpenRadius = 1;
Mat image, sharpen;
const char* window_name1 = "multiScaleSharpen";
Mat multiScaleSharpen(Mat Src, int Radius)
{
int rows = Src.rows;
int cols = Src.cols;
int cha = Src.channels();
Mat B1, B2, B3;
GaussianBlur(Src, B1, Size(Radius, Radius), 1.0, 1.0);
GaussianBlur(Src, B2, Size(Radius * 2 - 1, Radius * 2 - 1), 2.0, 2.0);
GaussianBlur(Src, B3, Size(Radius * 4 - 1, Radius * 4 - 1), 4.0, 4.0);
double w1 = 0.5;
double w2 = 0.5;
double w3 = 0.25;
cv::Mat dest = cv::Mat::zeros(Src.size(), Src.type());
for (size_t i = 0; i < rows; i++)
{
uchar* src_ptr = Src.ptr<uchar>(i);
uchar* dest_ptr = dest.ptr<uchar>(i);
uchar* B1_ptr = B1.ptr<uchar>(i);
uchar* B2_ptr = B2.ptr<uchar>(i);
uchar* B3_ptr = B3.ptr<uchar>(i);
for (size_t j = 0; j < cols; j++)
{
for (size_t c = 0; c < cha; c++)
{
int D1 = src_ptr[3 * j + c] - B1_ptr[3 * j + c];
int D2 = B1_ptr[3 * j + c] - B2_ptr[3 * j + c];
int D3 = B2_ptr[3 * j + c] - B3_ptr[3 * j + c];
int sign = (D1 > 0) ? 1 : -1;
dest_ptr[3 * j + c] = saturate_cast<uchar>((1 - w1 * sign)*D1 - w2 * D2 + w3 * D3 + src_ptr[3 * j + c]);
}
}
}
return dest;
}
// define a trackbar callback
static void onTrackbar(int, void*)
{
sharpen = multiScaleSharpen(image, sharpenRadius *2+1);
imshow(window_name1, sharpen);
}
static void help(const char** argv)
{
printf("\nThis sample demonstrates multiScaleSharpen detection\n"
"Call:\n"
" %s [image_name -- Default is lena.jpg]\n\n", argv[0]);
}
const char* keys =
{
"{help h||}{@image |lena.jpg|input image name}"
};
int main( int argc, const char** argv )
{
help(argv);
CommandLineParser parser(argc, argv, keys);
string filename = parser.get<string>(0);
image = imread(samples::findFile(filename), IMREAD_COLOR);
if(image.empty())
{
printf("Cannot read image file: %s\n", filename.c_str());
help(argv);
return -1;
}
// Create a window
namedWindow(window_name1, 1);
// create a toolbar
createTrackbar("Canny threshold default", window_name1, &sharpenRadius, 7, onTrackbar);
// Show the image
onTrackbar(0, 0);
// Wait for a key stroke; the same function arranges events processing
waitKey(0);
return 0;}
https://github.com/opencv/opencv/blob/master/samples/cpp/tutorial_code/core/mat_mask_operations/mat_mask_operations.cpp
给提供了:
void Sharpen(const Mat& myImage,Mat& Result)
{
//! [8_bit]
CV_Assert(myImage.depth() == CV_8U); // accept only uchar images
//! [8_bit]
//! [create_channels]
const int nChannels = myImage.channels();
Result.create(myImage.size(),myImage.type());
//! [create_channels]
//! [basic_method_loop]
for(int j = 1 ; j < myImage.rows-1; ++j)
{
const uchar* previous = myImage.ptr<uchar>(j - 1);
const uchar* current = myImage.ptr<uchar>(j );
const uchar* next = myImage.ptr<uchar>(j + 1);
uchar* output = Result.ptr<uchar>(j);
for(int i= nChannels;i < nChannels*(myImage.cols-1); ++i)
{
*output++ = saturate_cast<uchar>(5*current[i]
-current[i-nChannels] - current[i+nChannels] - previous[i] - next[i]);
}
}
//! [basic_method_loop]
//! [borders]
Result.row(0).setTo(Scalar(0));
Result.row(Result.rows-1).setTo(Scalar(0));
Result.col(0).setTo(Scalar(0));
Result.col(Result.cols-1).setTo(Scalar(0));
//! [borders]
}