I am using Open cv for creating RGB to HSI then doing a histogram. Then Fourier transform and back to HSI to RGB - visual-studio

I can not debug this programme. I am going to convert RGB to HSI and then Put a histogram in anyone channel. before Fourier and after Fourier.
#include "stdafx.h"
#include <opencv2/opencv.hpp>
#include <opencv\highgui.h>
#include <iostream>
// ass.cpp : Converts the given RGB image to HSI colour space then
// performs Fourier filtering on a particular channel.
//
using namespace std;
using namespace cv;
// Declarations of 4 unfinished functions
Mat rgb2hsi(const Mat& rgb); // converts RGB image to HSI space
Mat hsi2rgb(const Mat& hsi); // converts HSI image to RGB space
Mat histogram(const Mat& im); // returns the histogram of the selected channel in HSI space
// void filter(Mat& im);// // performs frequency-domain filtering on a single-channel image
int main(int argc, char* argv[])
{
if (argc < 2) // check number of arguments
{
cerr << "feed me something!!" << endl; // no arguments passed
return -1;
}
string path = argv[1];
Mat im; // load an RGB image
Mat hsi = rgb2hsi(im); // convert it to HSI space
Mat slices[3]; // 3 channels of the converted HSI image
im = imread(path); //try to load path
if (im.empty()) // loaded Sucessfully
{
cerr << "I Cannot load the file : ";
return -1;
}
imshow("BEFORE", im);
split(hsi, slices); // split up the packed HSI image into an array of matrices
Mat& h = slices[0];
Mat& s = slices[1];
Mat& i = slices[2]; // references to H, S, and I layers
Mat hist1, hist2; // histogram of the selected channel before and after filtering
Going to apply histogram. May be I miss some header. draw is not taken.
Mat histogram(const Mat& im)
{
Mat hist;
const float range[] = { 0, 255 };
const int channels[] = { 0 };
const int bins = range[1] - range[0];
const int dims[] = { bins, 1 };
const Size binSize(2, 240);
const float* ranges[] = { range };
// calculate the histogram
calcHist(&im, 1, channels, Mat(), hist, 1, dims, ranges);
Mat draw = Mat::zeros(binSize.height, binSize.width * bins, CV_8UC3);
double maxVal;
minMaxLoc(hist, NULL, &maxVal, 0, 0);
for (int b = 0; b < bins; b++)
{
float val = hist.at<float>(b, 0);
int x0 = binSize.width * b;
int y0 = draw.rows - val / maxVal * binSize.height + 1;
int x1 = binSize.width * (b + 1) - 1;
int y1 = draw.rows - 1;
rectangle(draw,0, cv::(Point(x0, y0), cv::Point(x1, y1)), Scalar::all(255), CV_FILLED);
}
return draw;
}
imwrite("input-original.png", rgb); // write the input image
imwrite("hist-original.png", histogram(h)); // write the histogram of the selected channel
filter(h); // perform filtering
merge(slices, 3, hsi); // combine the separated H, S, and I layers to a big packed matrix
rgb = hsi2rgb(hsi); // convert HSI back to RGB colour space
imwrite("input-filtered.png", rgb); // write the filtered image
imwrite("hist-filtered.png", histogram(h)); // and the histogram of the filtered channel
return 0;
}
Mat rgb2hsi(const Mat& rgb)
{
Mat slicesRGB[3];
Mat slicesHSI[3];
Mat &r = slicesRGB[0], &g = slicesRGB[1], &b = slicesRGB[2];
Mat &h = slicesHSI[0], &s = slicesHSI[1], &i = slicesHSI[2];
split(rgb, slicesRGB);
//
// TODO: implement colour conversion RGB => HSI
//
// begin of conversion code
h = r * 1.0f;
s = g * 1.0f;
i = b * 1.0f;
// end of conversion code
Mat hsi;
merge(slicesHSI, 3, hsi);
return hsi;
}
Mat hsi2rgb(const Mat& hsi)
{
Mat slicesRGB[3];
Mat slicesHSI[3];
Mat &r = slicesRGB[0], &g = slicesRGB[1], &b = slicesRGB[2];
Mat &h = slicesHSI[0], &s = slicesHSI[1], &i = slicesHSI[2];
split(hsi, slicesHSI);
// begin of conversion code
r = h * 1.0f;
g = s * 1.0f;
b = i * 1.0f;
// end of conversion code
Mat rgb;
merge(slicesRGB, 3, rgb);
return rgb;
}
Mat histogram(const Mat& im)
{
Mat hist;
const float range[] = { 0, 255 };
const int channels[] = { 0 };
const int bins = range[1] - range[0];
const int dims[] = { bins, 1 };
const Size binSize(2, 240);
const float* ranges[] = { range };
// calculate the histogram
calcHist(&im, 1, channels, Mat(), hist, 1, dims, ranges);
Mat draw = Mat::zeros(binSize.height, binSize.width * bins, CV_8UC3);
double maxVal;
minMaxLoc(hist, NULL, &maxVal, 0, 0);
for (int b = 0; b < bins; b++)
{
float val = hist.at<float>(b, 0);
int x0 = binSize.width * b;
int y0 = draw.rows - val / maxVal * binSize.height + 1;
int x1 = binSize.width * (b + 1) - 1;
int y1 = draw.rows - 1;
rectangle(draw, Point(x0, y0), Point(x1, y1), Scalar::all(255), CV_FILLED);
}
return draw;
}
void filter(Mat& im)
{
int type = im.type();
// Convert pixel data from unsigned 8-bit integers (0~255)
// to 32-bit floating numbers, as required by cv::dft
if (type != CV_32F) im.convertTo(im, CV_32F);
// Perform 2-D Discrete Fourier Transform
Mat f;
dft(im, f, DFT_COMPLEX_OUTPUT + DFT_SCALE); // do DFT
// Separate the packed complex matrix to two matrices
Mat complex[2];
Mat& real = complex[0]; // the real part
Mat& imag = complex[1]; // the imaginary part
split(f, complex); // dft(im) => {real,imag}
// Frequency domain filtering
int xc = im.cols / 2; // find (xc,yc) the highest
int yc = im.rows / 2; // frequency component
for (int y = 0; y < im.rows; y++) // go through each row..
{
for (int x = 0; x < im.cols; x++) // then through each column..
{
//
// TODO: Design your formula here to decide if the component is
// discarded or kept.
//
if (false) // override this condition
{
real.at<float>(y, x) = 0;
imag.at<float>(y, x) = 0;
}
}
}
// Pack the real and imaginary parts
// back to the 2-channel matrix
merge(complex, 2, f); // {real,imag} => f
// Perform 2-D Inverse Discrete Fourier Transform
idft(f, im, DFT_REAL_OUTPUT); // do iDFT
// convert im back to it's original type
im.convertTo(im, type);
}
Error List
1 IntelliSense: expected a ';' d:\709
Tutorial\Dibya_project\Dibya_project\Dibya_project.cpp 48 2 Dibya_project
2 IntelliSense: identifier "draw" is undefined d:\709
Tutorial\Dibya_project\Dibya_project\Dibya_project.cpp 70 13 Dibya_project
3 IntelliSense: no instance of overloaded function "rectangle"
matches the argument list
argument types are: (, int, , cv::Scalar_, int) d:\709
Tutorial\Dibya_project\Dibya_project\Dibya_project.cpp 72 4 Dibya_project
4 IntelliSense: expected an identifier d:\709
Tutorial\Dibya_project\Dibya_project\Dibya_project.cpp 72 26 Dibya_project
5 IntelliSense: no instance of constructor "cv::Point_<Tp>::Point
[with _Tp=int]" matches the argument list
argument types are: (, double __cdecl (double _X)) d:\709 Tutorial\Dibya_project\Dibya_project\Dibya_project.cpp 72 27 Dibya_project

broken here (in Mat histogram(...)):
rectangle(draw,0, cv::(Point(x0, y0), cv::Point(x1, y1)), Scalar::all(255), CV_FILLED);
should be either:
rectangle(draw,0, cv::Rect(Point(x0, y0), cv::Point(x1, y1)), Scalar::all(255), CV_FILLED);
or:
rectangle(draw,0, Point(x0, y0), cv::Point(x1, y1), Scalar::all(255), CV_FILLED);

I think there is a typo in including the highgui header file.

Related

Maximum float value in 10-bit image in WIC

I'm trying to convert a HDR image float array I load to a 10-bit DWORD with WIC.
The type of the loading file is GUID_WICPixelFormat128bppPRGBAFloat and I got an array of 4 floats per color.
When I try to convert these to 10 bit as follows:
struct RGBX
{
unsigned int b : 10;
unsigned int g : 10;
unsigned int r : 10;
int a : 2;
} rgbx;
(which is the format requested by the NVIDIA encoding library for 10-bit rgb),
then I assume I have to divide each of the floats by 1024.0f in order to get them inside the 10 bits of a DWORD.
However, I notice that some of the floats are > 1, which means that their range is not [0,1] as it happens when the image is 8 bit.
What would their range be? How to store a floating point color into a 10-bits integer?
I'm trying to use the NVidia's HDR encoder which requires an ARGB10 like the above structure.
How is the 10 bit information of a color stored as a floating point number?
Btw I tried to convert with WIC but conversion from GUID_WICPixelFormat128bppPRGBAFloat to GUID_WICPixelFormat32bppR10G10B10A2 fails.
HRESULT ConvertFloatTo10(const float* f, int wi, int he, std::vector<DWORD>& out)
{
CComPtr<IWICBitmap> b;
wbfact->CreateBitmapFromMemory(wi, he, GUID_WICPixelFormat128bppPRGBAFloat, wi * 16, wi * he * 16, (BYTE*)f, &b);
CComPtr<IWICFormatConverter> wf;
wbfact->CreateFormatConverter(&wf);
wf->Initialize(b, GUID_WICPixelFormat32bppR10G10B10A2, WICBitmapDitherTypeNone, 0, 0, WICBitmapPaletteTypeCustom);
// This last call fails with 0x88982f50 : The component cannot be found.
}
Edit: I found a paper (https://hal.archives-ouvertes.fr/hal-01704278/document), is this relevant to this question?
Floating-point color content that is greater than the 0..1 range is High Dynamic Range (HDR) content. If you trivially convert it to 10:10:10:2 UNORM then you are using 'clipping' for values over 1. This doesn't give good results.
SDR 10:10:10 or 8:8:8
You should instead use tone-mapping which converts the HDR signal to a SDR (Standard Dynamic Range a.k.a. 0..1) before or as part of doing the conversion to 10:10:10:2.
There a many different approaches to tone-mapping, but a common 'generic' solution is the Reinhard tone-mapping operator. Here's an implementation using DirectXTex.
std::unique_ptr<ScratchImage> timage(new (std::nothrow) ScratchImage);
if (!timage)
{
wprintf(L"\nERROR: Memory allocation failed\n");
return 1;
}
// Compute max luminosity across all images
XMVECTOR maxLum = XMVectorZero();
hr = EvaluateImage(image->GetImages(), image->GetImageCount(), image->GetMetadata(),
[&](const XMVECTOR* pixels, size_t w, size_t y)
{
UNREFERENCED_PARAMETER(y);
for (size_t j = 0; j < w; ++j)
{
static const XMVECTORF32 s_luminance = { { { 0.3f, 0.59f, 0.11f, 0.f } } };
XMVECTOR v = *pixels++;
v = XMVector3Dot(v, s_luminance);
maxLum = XMVectorMax(v, maxLum);
}
});
if (FAILED(hr))
{
wprintf(L" FAILED [tonemap maxlum] (%08X%ls)\n", static_cast<unsigned int>(hr), GetErrorDesc(hr));
return 1;
}
maxLum = XMVectorMultiply(maxLum, maxLum);
hr = TransformImage(image->GetImages(), image->GetImageCount(), image->GetMetadata(),
[&](XMVECTOR* outPixels, const XMVECTOR* inPixels, size_t w, size_t y)
{
UNREFERENCED_PARAMETER(y);
for (size_t j = 0; j < w; ++j)
{
XMVECTOR value = inPixels[j];
const XMVECTOR scale = XMVectorDivide(
XMVectorAdd(g_XMOne, XMVectorDivide(value, maxLum)),
XMVectorAdd(g_XMOne, value));
const XMVECTOR nvalue = XMVectorMultiply(value, scale);
value = XMVectorSelect(value, nvalue, g_XMSelect1110);
outPixels[j] = value;
}
}, *timage);
if (FAILED(hr))
{
wprintf(L" FAILED [tonemap apply] (%08X%ls)\n", static_cast<unsigned int>(hr), GetErrorDesc(hr));
return 1;
}
HDR10
UPDATE: If you are trying to convert HDR floating-point content to an "HDR10" signal, then you need to do:
Color-space rotate from Rec.709 or P3D65 to Rec.2020.
Normalize for 'paper white' / 10,000 nits.
Apply the ST.2084 gamma curve.
Quantize to 10-bit.
// HDTV to UHDTV (Rec.709 color primaries into Rec.2020)
const XMMATRIX c_from709to2020 =
{
0.6274040f, 0.0690970f, 0.0163916f, 0.f,
0.3292820f, 0.9195400f, 0.0880132f, 0.f,
0.0433136f, 0.0113612f, 0.8955950f, 0.f,
0.f, 0.f, 0.f, 1.f
};
// DCI-P3-D65 https://en.wikipedia.org/wiki/DCI-P3 to UHDTV (DCI-P3-D65 color primaries into Rec.2020)
const XMMATRIX c_fromP3D65to2020 =
{
0.753845f, 0.0457456f, -0.00121055f, 0.f,
0.198593f, 0.941777f, 0.0176041f, 0.f,
0.047562f, 0.0124772f, 0.983607f, 0.f,
0.f, 0.f, 0.f, 1.f
};
// Custom Rec.709 into Rec.2020
const XMMATRIX c_fromExpanded709to2020 =
{
0.6274040f, 0.0457456f, -0.00121055f, 0.f,
0.3292820f, 0.941777f, 0.0176041f, 0.f,
0.0433136f, 0.0124772f, 0.983607f, 0.f,
0.f, 0.f, 0.f, 1.f
};
inline float LinearToST2084(float normalizedLinearValue)
{
const float ST2084 = pow((0.8359375f + 18.8515625f * pow(abs(normalizedLinearValue), 0.1593017578f)) / (1.0f + 18.6875f * pow(abs(normalizedLinearValue), 0.1593017578f)), 78.84375f);
return ST2084; // Don't clamp between [0..1], so we can still perform operations on scene values higher than 10,000 nits
}
// You can adjust this up to 10000.f
float paperWhiteNits = 200.f;
hr = TransformImage(image->GetImages(), image->GetImageCount(), image->GetMetadata(),
[&](XMVECTOR* outPixels, const XMVECTOR* inPixels, size_t w, size_t y)
{
UNREFERENCED_PARAMETER(y);
const XMVECTOR paperWhite = XMVectorReplicate(paperWhiteNits);
for (size_t j = 0; j < w; ++j)
{
XMVECTOR value = inPixels[j];
XMVECTOR nvalue = XMVector3Transform(value, c_from709to2020);
// Some people prefer the look of using c_fromP3D65to2020
// or c_fromExpanded709to2020 instead.
// Convert to ST.2084
nvalue = XMVectorDivide(XMVectorMultiply(nvalue, paperWhite), c_MaxNitsFor2084);
XMFLOAT4A tmp;
XMStoreFloat4A(&tmp, nvalue);
tmp.x = LinearToST2084(tmp.x);
tmp.y = LinearToST2084(tmp.y);
tmp.z = LinearToST2084(tmp.z);
nvalue = XMLoadFloat4A(&tmp);
value = XMVectorSelect(value, nvalue, g_XMSelect1110);
outPixels[j] = value;
}
}, *timage);
You should really take a look at texconv.
Reference
Reinhard et al., "Photographic tone reproduction for digital images", ACM Transactions on Graphics, Volume 21, Issue 3 (July 2002). ACM DL.
#ChuckWalbourn answer is helpful, however I don't want to tonemap to [0,1] as there is no point in tonemapping to SDR then going to 10-bit HDR.
What I 'd think it's correct is to scale to [0,4] instead by first using g_XMFour.
const XMVECTOR scale = XMVectorDivide(
XMVectorAdd(g_XMFour, XMVectorDivide(v, maxLum)),
XMVectorAdd(g_XMFour, v));
then using a specialized 10-bit store which scales by 255 instead of 1023:
void XMStoreUDecN4a(DirectX::PackedVector::XMUDECN4* pDestination,DirectX::FXMVECTOR V)
{
using namespace DirectX;
XMVECTOR N;
static const XMVECTOR Scale = { 255.0f, 255.0f, 255.0f, 3.0f };
assert(pDestination);
N = XMVectorClamp(V, XMVectorZero(), g_XMFour);
N = XMVectorMultiply(N, Scale);
pDestination->v = ((uint32_t)DirectX::XMVectorGetW(N) << 30) |
(((uint32_t)DirectX::XMVectorGetZ(N) & 0x3FF) << 20) |
(((uint32_t)DirectX::XMVectorGetY(N) & 0x3FF) << 10) |
(((uint32_t)DirectX::XMVectorGetX(N) & 0x3FF));
}
And then a specialized 10-bit load which divides with 255 instead of 1023:
DirectX::XMVECTOR XMLoadUDecN4a(DirectX::PackedVector::XMUDECN4* pSource)
{
using namespace DirectX;
fourx vectorOut;
uint32_t Element;
Element = pSource->v & 0x3FF;
vectorOut.r = (float)Element / 255.f;
Element = (pSource->v >> 10) & 0x3FF;
vectorOut.g = (float)Element / 255.f;
Element = (pSource->v >> 20) & 0x3FF;
vectorOut.b = (float)Element / 255.f;
vectorOut.a = (float)(pSource->v >> 30) / 3.f;
const DirectX::XMVECTORF32 j = { vectorOut.r,vectorOut.g,vectorOut.b,vectorOut.a };
return j;
}

How to deblur image using fourier transform in open-cv or emgu-cv?

i saw this video about debluring images using fourier transform in matlab
video
and i want to convert the code in emgu cv
my code in emgucv :
string path = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
Image<Bgr, byte> img = new Image<Bgr, byte>(#"lal.png");
//blur the image
Image<Gray, byte> gray = img.Convert<Gray, byte>().SmoothBlur(31,31);
//convert image to float and get the fourier transform
Mat g_fl = gray.Convert<Gray, float>().Mat;
Matrix<float> dft_image = new Matrix<float>(g_fl.Size);
CvInvoke.Dft(g_fl, dft_image, Emgu.CV.CvEnum.DxtType.Forward, 0);
//here i make an image of kernel with size of the original
Image<Gray, float> ker = new Image<Gray, float>(img.Size);
ker.SetZero();
for (int x = 0; x < 31; x++)
{
for (int y = 0; y < 31; y++)
{
//31 * 31= 961
ker[y, x] = new Gray(1/961);
}
}
//get the fourier of the kernel
Matrix<float> dft_blur = new Matrix<float>(g_fl.Size);
CvInvoke.Dft(ker, dft_blur, Emgu.CV.CvEnum.DxtType.Forward, 0);
// fouier image / fourier blur
Matrix<float> res = new Matrix<float>(g_fl.Size);
for (int x=0;x<g_fl.Cols;x++)
{
for (int y = 0; y < g_fl.Rows; y++)
{
res[y, x] = dft_image[y, x] / dft_blur[y, x];
}
}
//get the inverse of fourier
Image<Gray, float> ready = new Image<Gray, float>(g_fl.Size);
CvInvoke.Dft(res, ready, Emgu.CV.CvEnum.DxtType.Inverse, 0);
CvInvoke.Imshow("deblur", ready.Convert<Gray,byte>());
CvInvoke.Imshow("original", gray);
CvInvoke.WaitKey(0);
but the result is black and not working , where is the mistake in my code
if you have a code in opencv python you can post it :)??
Thanks :)
My old implementation of wiener filter:
#include "stdafx.h"
#pragma once
#pragma comment(lib, "opencv_legacy220.lib")
#pragma comment(lib, "opencv_core220.lib")
#pragma comment(lib, "opencv_highgui220.lib")
#pragma comment(lib, "opencv_imgproc220.lib")
#include "c:\Users\Andrey\Documents\opencv\include\opencv\cv.h"
#include "c:\Users\Andrey\Documents\opencv\include\opencv\cxcore.h"
#include "c:\Users\Andrey\Documents\opencv\include\opencv\highgui.h"
#include <string>
#include <iostream>
#include <complex>
using namespace std;
using namespace cv;
//----------------------------------------------------------
// Compute real and implicit parts of FFT for given image
//----------------------------------------------------------
void ForwardFFT(Mat &Src, Mat *FImg)
{
int M = getOptimalDFTSize( Src.rows );
int N = getOptimalDFTSize( Src.cols );
Mat padded;
copyMakeBorder(Src, padded, 0, M - Src.rows, 0, N - Src.cols, BORDER_CONSTANT, Scalar::all(0));
// Create complex representation of our image
// planes[0] Real part, planes[1] Implicit part (zeros)
Mat planes[] = {Mat_<double>(padded), Mat::zeros(padded.size(), CV_64F)};
Mat complexImg;
merge(planes, 2, complexImg);
dft(complexImg, complexImg);
// As result, we also have Re and Im planes
split(complexImg, planes);
// Crop specter, if it have odd number of rows or cols
planes[0] = planes[0](Rect(0, 0, planes[0].cols & -2, planes[0].rows & -2));
planes[1] = planes[1](Rect(0, 0, planes[1].cols & -2, planes[1].rows & -2));
FImg[0]=planes[0].clone();
FImg[1]=planes[1].clone();
}
//----------------------------------------------------------
// Restore our image using specter
//----------------------------------------------------------
void InverseFFT(Mat *FImg,Mat &Dst)
{
Mat complexImg;
merge(FImg, 2, complexImg);
// Apply inverse FFT
idft(complexImg, complexImg);
split(complexImg, FImg);
Dst=FImg[0];
}
//----------------------------------------------------------
// Wiener filter
//----------------------------------------------------------
void wienerFilter(Mat &src,Mat &dst,Mat &_h,double k)
{
//---------------------------------------------------
// small number for numeric stability
//---------------------------------------------------
const double eps=1E-8;
//---------------------------------------------------
int ImgW=src.size().width;
int ImgH=src.size().height;
//--------------------------------------------------
Mat Yf[2];
ForwardFFT(src,Yf);
//--------------------------------------------------
Mat h;
h.create(ImgH,ImgW,CV_64F);
h=0;
_h.copyTo(h(Rect(0, 0, _h.size().width, _h.size().height)));
Mat Hf[2];
ForwardFFT(h,Hf);
//--------------------------------------------------
Mat Fu[2];
Fu[0].create(ImgH,ImgW,CV_64F);
Fu[1].create(ImgH,ImgW,CV_64F);
complex<double> a;
complex<double> b;
complex<double> c;
double Hf_Re;
double Hf_Im;
double Phf;
double hfz;
double hz;
double A;
for (int i=0;i<Hf[0].size().height;i++)
{
for (int j=0;j<Hf[0].size().width;j++)
{
Hf_Re=Hf[0].at<double>(i,j);
Hf_Im=Hf[1].at<double>(i,j);
Phf = Hf_Re*Hf_Re+Hf_Im*Hf_Im;
hfz=(Phf<eps)*eps;
hz =(h.at<double>(i,j)>0);
A=Phf/(Phf+hz+k);
a=complex<double>(Yf[0].at<double>(i,j),Yf[1].at<double>(i,j));
b=complex<double>(Hf_Re+hfz,Hf_Im+hfz);
c=a/b; // Deconvolution
// Other we do to remove division by 0
Fu[0].at<double>(i,j)=(c.real()*A);
Fu[1].at<double>(i,j)=(c.imag()*A);
}
}
//--------------------------------------------------
Fu[0]/=(ImgW*ImgH);
Fu[1]/=(ImgW*ImgH);
//--------------------------------------------------
InverseFFT(Fu,dst);
// remove out of rane values
for (int i=0;i<Hf[0].size().height;i++)
{
for (int j=0;j<Hf[0].size().width;j++)
{
if(dst.at<double>(i,j)>215){dst.at<double>(i,j)=215;}
if(dst.at<double>(i,j)<(-40)){dst.at<double>(i,j)=(-40);}
}
}
}
//----------------------------------------------------------
// Main
//----------------------------------------------------------
int _tmain(int argc, _TCHAR* argv[])
{
// Input image
Mat img;
// Load it from drive
img=imread("data/motion_fuzzy_lena.bmp",0);
//---------------------------------------------
imshow("Src image", img);
// Image size
int ImgW=img.size().width;
int ImgH=img.size().height;
// Deconvolution kernel (coefficient sum must be 1)
// Image was blurred using same kernel
Mat h;
h.create(1,10,CV_64F);
h=1/double(h.size().width*h.size().height);
// Apply filter
wienerFilter(img,img,h,0.05);
normalize(img,img, 0, 1, CV_MINMAX);
imshow("Result image", img);
cvWaitKey(0);
return 0;
}
The result:

How to remove edge of house using opencv

How to remove the circle content of above image. The original image is showed below:
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <cmath>
#include <iostream>
using namespace cv;
using namespace std;
/**
* Helper function to find a cosine of angle between vectors
* from pt0->pt1 and pt0->pt2
*/
static double angle(cv::Point pt1, cv::Point pt2, cv::Point pt0)
{
double dx1 = pt1.x - pt0.x;
double dy1 = pt1.y - pt0.y;
double dx2 = pt2.x - pt0.x;
double dy2 = pt2.y - pt0.y;
return (dx1*dx2 + dy1*dy2) / sqrt((dx1*dx1 + dy1*dy1)*(dx2*dx2 + dy2*dy2) + 1e-10);
}
/**
* Helper function to display text in the center of a contour
*/
void setLabel(cv::Mat& im, const std::string label, std::vector<cv::Point>& contour)
{
int fontface = cv::FONT_HERSHEY_SIMPLEX;
double scale = 0.4;
int thickness = 1;
int baseline = 0;
cv::Size text = cv::getTextSize(label, fontface, scale, thickness, &baseline);
cv::Rect r = cv::boundingRect(contour);
cv::Point pt(r.x + ((r.width - text.width) / 2), r.y + ((r.height + text.height) / 2));
cv::rectangle(im, pt + cv::Point(0, baseline), pt + cv::Point(text.width, -text.height), CV_RGB(255, 0, 255), CV_FILLED);
cv::putText(im, label, pt, fontface, scale, CV_RGB(0, 0, 0), thickness, 8);
}
int main()
{
//cv::Mat src = cv::imread("polygon.png");
Mat src = imread("3.bmp");//2.png 3.jpg
Mat src_copy;
src.copyTo(src_copy);
resize(src, src, cvSize(0, 0), 1, 1);
cout << "src type " << src.type() << endl;
Mat mask(src.size(), src.type(), Scalar(0));
if (src.empty())
return -1;
// Convert to grayscale
cv::Mat gray;
if (src.type() != CV_8UC1)
cv::cvtColor(src, gray, CV_BGR2GRAY);
// Use Canny instead of threshold to catch squares with gradient shading
cv::Mat bw;
cv::Canny(gray, bw, 0, 50, 5);
// Find contours
std::vector<std::vector<cv::Point> > contours;
cv::findContours(bw.clone(), contours, CV_RETR_LIST, CV_CHAIN_APPROX_NONE);
drawContours(src, contours, -1, Scalar(0, 255, 0), 2);
std::vector<cv::Point> approx;
cv::Mat dst = src.clone();
for (int i = 0; i < contours.size(); i++)
{
// Approximate contour with accuracy proportional
// to the contour perimeter
cv::approxPolyDP(cv::Mat(contours[i]), approx, cv::arcLength(cv::Mat(contours[i]), true)*0.1, true);
// Skip small or non-convex objects
if (std::fabs(cv::contourArea(contours[i])) < 500 || !cv::isContourConvex(approx))
continue;
if (approx.size() == 3)
{
//setLabel(dst, "TRI", contours[i]); // Triangles
}
else if (approx.size() >= 4 && approx.size() <= 6)
{
// Number of vertices of polygonal curve
int vtc = approx.size();
// Get the cosines of all corners
std::vector<double> cos;
for (int j = 2; j < vtc + 1; j++)
cos.push_back(angle(approx[j%vtc], approx[j - 2], approx[j - 1]));
// Sort ascending the cosine values
std::sort(cos.begin(), cos.end());
// Get the lowest and the highest cosine
double mincos = cos.front();
double maxcos = cos.back();
// Use the degrees obtained above and the number of vertices
// to determine the shape of the contour
if (vtc == 4 && mincos >= -0.2 && maxcos <= 0.5)
{
Mat element = getStructuringElement(MORPH_RECT, Size(13, 13));
setLabel(dst, "RECT", contours[i]);
drawContours(mask, contours, i, Scalar(255, 255, 255), CV_FILLED);
dilate(mask, mask, element);
src_copy = src_copy - mask;
}
else if (vtc == 5 && mincos >= -0.34 && maxcos <= -0.27)
setLabel(dst, "PENTA", contours[i]);
else if (vtc == 6 && mincos >= -0.55 && maxcos <= -0.45)
setLabel(dst, "HEXA", contours[i]);
}
else
{
// Detect and label circles
double area = cv::contourArea(contours[i]);
cv::Rect r = cv::boundingRect(contours[i]);
int radius = r.width / 2;
if (std::abs(1 - ((double)r.width / r.height)) <= 0.2 &&
std::abs(1 - (area / (CV_PI * std::pow(radius, 2)))) <= 0.2)
setLabel(dst, "CIR", contours[i]);
}
}
//cv::imshow("src", src);
imwrite("mask.jpg", mask);
imwrite("src.jpg", src_copy);
imwrite("dst.jpg", dst);
cv::imshow("dst", dst);
cv::waitKey(0);
return 0;
}

DX11 convert pixel format BGRA to RGBA

I have currently the problem that a library creates a DX11 texture with BGRA pixel format.
But the displaying library can only display RGBA correctly. (This means the colors are swapped in the rendered image)
After looking around I found a simple for-loop to solve the problem, but the performance is not very good and scales bad with higher resolutions. I'm new to DirectX and maybe I just missed a simple function to do the converting.
// Get the image data
unsigned char* pDest = view->image->getPixels();
// Prepare source texture
ID3D11Texture2D* pTexture = static_cast<ID3D11Texture2D*>( tex );
// Get context
ID3D11DeviceContext* pContext = NULL;
dxDevice11->GetImmediateContext(&pContext);
// Copy data, fast operation
pContext->CopySubresourceRegion(texStaging, 0, 0, 0, 0, tex, 0, nullptr);
// Create mapping
D3D11_MAPPED_SUBRESOURCE mapped;
HRESULT hr = pContext->Map( texStaging, 0, D3D11_MAP_READ, 0, &mapped );
if ( FAILED( hr ) )
{
return;
}
// Calculate size
const size_t size = _width * _height * 4;
// Access pixel data
unsigned char* pSrc = static_cast<unsigned char*>( mapped.pData );
// Offsets
int offsetSrc = 0;
int offsetDst = 0;
int rowOffset = mapped.RowPitch % _width;
// Loop through it, BRGA to RGBA conversation
for (int row = 0; row < _height; ++row)
{
for (int col = 0; col < _width; ++col)
{
pDest[offsetDst] = pSrc[offsetSrc+2];
pDest[offsetDst+1] = pSrc[offsetSrc+1];
pDest[offsetDst+2] = pSrc[offsetSrc];
pDest[offsetDst+3] = pSrc[offsetSrc+3];
offsetSrc += 4;
offsetDst += 4;
}
// Adjuste offset
offsetSrc += rowOffset;
}
// Unmap texture
pContext->Unmap( texStaging, 0 );
Solution:
Texture2D txDiffuse : register(t0);
SamplerState texSampler : register(s0);
struct VSScreenQuadOutput
{
float4 Position : SV_POSITION;
float2 TexCoords0 : TEXCOORD0;
};
float4 PSMain(VSScreenQuadOutput input) : SV_Target
{
return txDiffuse.Sample(texSampler, input.TexCoords0).rgba;
}
Obviously iterating over a texture on you CPU is not the most effective way. If you know that colors in a texture are always swapped like that and you don't want to modify the texture itself in your C++ code, the most straightforward way would be to do it in the pixel shader. When you sample the texture, simply swap colors there. You won't even notice any performance drop.

Which is best simple Gaussian blur or FFT of Gaussian blur for sigma=20?

I'm making a program to blur a 16 bit grayscale image in CUDA.
In my program, if I use a Gaussian blur function with sigma = 20 or 30, it takes a lot of time, while it is fast with sigma = 2.0 or 3.0.
I've read in some web site that Guaussian blur with FFT is good for large kernel size or large sigma value:
Is It really true ?
Which algorithm should I use: simple Gaussian blur or Gaussian blur with FFT ?
My code for Guassian Blur is below. In my code , is there something wrong or not ?
enter code here
__global__
void gaussian_blur(
unsigned short* const blurredChannel, // return value: blurred channel (either red, green, or blue)
const unsigned short* const inputChannel, // red, green, or blue channel from the original image
int rows,
int cols,
const float* const filterWeight, // gaussian filter weights. The weights look like a bell shape.
int filterWidth // number of pixels in x and y directions for calculating average blurring
)
{
int r = blockIdx.y * blockDim.y + threadIdx.y; // current row
int c = blockIdx.x * blockDim.x + threadIdx.x; // current column
if ((r >= rows) || (c >= cols))
{
return;
}
int half = filterWidth / 2;
float blur = 0.f; // will contained blurred value
int width = cols - 1;
int height = rows - 1;
for (int i = -half; i <= half; ++i) // rows
{
for (int j = -half; j <= half; ++j) // columns
{
// Clamp filter to the image border
int h = min(max(r + i, 0), height);
int w = min(max(c + j, 0), width);
// Blur is a product of current pixel value and weight of that pixel.
// Remember that sum of all weights equals to 1, so we are averaging sum of all pixels by their weight.
int idx = w + cols * h; // current pixel index
float pixel = static_cast<float>(inputChannel[idx]);
idx = (i + half) * filterWidth + j + half;
float weight = filterWeight[idx];
blur += pixel * weight;
}
}
blurredChannel[c + r * cols] = static_cast<unsigned short>(blur);
}
void createFilter(float *gKernel,double sigma,int radius)
{
double r, s = 2.0 * sigma * sigma;
// sum is for normalization
double sum = 0.0;
// generate 9*9 kernel
int m=0;
for (int x = -radius; x <= radius; x++)
{
for(int y = -radius; y <= radius; y++)
{
r = std::sqrtf(x*x + y*y);
gKernel[m] = (exp(-(r*r)/s))/(3.14 * s);
sum += gKernel[m];
m++;
}
}
m=0;
// normalize the Kernel
for(int i = 0; i < (radius*2 +1); ++i)
for(int j = 0; j < (radius*2 +1); ++j)
gKernel[m++] /= sum;
}
int main()
{
cudaError_t cudaStatus;
const int size =81;
float gKernel[size];
float *dev_p=0;
cudaStatus = cudaMalloc((void**)&dev_p, size * sizeof(float));
if (cudaStatus != cudaSuccess) {
fprintf(stderr, "cudaMemcpy failed!");
}
createFilter(gKernel,20.0,4);
cudaStatus = cudaMemcpy(dev_p, gKernel, size* sizeof(float), cudaMemcpyHostToDevice);
if (cudaStatus != cudaSuccess) {
fprintf(stderr, "cudaMemcpy failed!");
}
/* i read image Buffere in unsigned short that code is not added here ,becouse it is large , and copy image data of buffere from host to device*/
/* So, suppose i have unsigned short *d_img which contain image data */
cudaMalloc( (void**)&d_img, length* sizeof(unsigned short));
cudaMalloc( (void**)&d_blur_img, length* sizeof(unsigned short));
static const int BLOCK_WIDTH = 32;
int image_width=1580.0,image_height=1050.0;
int x = static_cast<int>(ceilf(static_cast<float>(image_width) / BLOCK_WIDTH));
int y = static_cast<int>(ceilf(static_cast<float>((image_height) ) / BLOCK_WIDTH));
const dim3 grid (x, y, 1); // number of blocks
const dim3 block(BLOCK_WIDTH, BLOCK_WIDTH, 1);
gaussian_blur<<<grid,block>>>(d_blur_img,d_img,1050.0,1580.0,dev_p,9.0);
cudaDeviceSynchronize();
/* after bluring image i will copied buffer from Device to Host and free gpu memory */
cudaFree(d_img);
cudaFree(d_blur_img);
cudaFree(dev_p);
return 0;
}
Short answer: both algorithms are good with respect to image blurring, so feel free to pick the best (fastest) one for your use case.
Kernel size and sigma value are directly correlated: the greater the sigma, the larger the kernel (and thus the more operations-per-pixel to get the final result).
If you implemented a naive convolution, then you should try a separable convolution implementation instead; it will reduce the computation time by an order of magnitude already.
Now some more insight: they implement almost the same Gaussian blurring operation. Why almost ? It's because taking the FFT of an image does implicitly periodize it. Hence, at the border of the image, the convolution kernel sees an image that has been wrapped around its edge. This is called circular convolution (because of the wrapping). On the other hand, Gaussian blur implements a simple linear convolution.

Resources