I'm writing a gaussian filter, and my goal is to match the gaussian blur filter in photoshop as closely as possible. This is my first image processing endeavor. Some problems/questions I have are...
Further blurring an image with my filter darkens it, while photoshop’s seems to lighten it.
The deviation value (“sigma,” in my code) I’m using is r/3, which results in the gaussian curve having approached about 0.0001 within the matrix...is there a better way to determine this value?
How does photoshop (or most people) handle image borders for this type of blur?
int matrixDimension = (radius*2)+1;
float sigma = radius/3;
float twoSigmaSquared = 2*pow(sigma, 2);
float oneOverSquareRootOfTwoPiSigmaSquared = 1/(sqrt(M_PI*twoSigmaSquared));
float kernel[matrixDimension];
int index = 0;
for (int offset = -radius; offset <= radius; offset++) {
float xSquared = pow(offset, 2);
float exponent = -(xSquared/twoSigmaSquared);
float eToThePower = pow(M_E, exponent);
float multFactor = oneOverSquareRootOfTwoPiSigmaSquared*eToThePower;
kernel[index] = multFactor;
index++;
}
//Normalize the kernel such that all its values will add to 1
float sum = 0;
for (int i = 0; i < matrixDimension; i++) {
sum += kernel[i];
}
for (int i = 0; i < matrixDimension; i++) {
kernel[i] = kernel[i]/sum;
}
//Blur horizontally
for (int row = 0; row < imageHeight; row++) {
for (int column = 0; column < imageWidth; column++) {
int currentPixel = (row*imageWidth)+column;
int sum1 = 0;
int sum2 = 0;
int sum3 = 0;
int sum4 = 0;
int index = 0;
for (int offset = -radius; offset <= radius; offset++) {
if (!(column+offset < 0) && !(column+offset > imageWidth-1)) {
int firstByteOfPixelWereLookingAtInSrcData = (currentPixel+offset)*4;
int in1 = srcData[firstByteOfPixelWereLookingAtInSrcData];
int in2 = srcData[firstByteOfPixelWereLookingAtInSrcData+1];
int in3 = srcData[firstByteOfPixelWereLookingAtInSrcData+2];
int in4 = srcData[firstByteOfPixelWereLookingAtInSrcData+3];
sum1 += (int)(in1 * kernel[index]);
sum2 += (int)(in2 * kernel[index]);
sum3 += (int)(in3 * kernel[index]);
sum4 += (int)(in4 * kernel[index]);
}
index++;
}
int currentPixelInData = currentPixel*4;
destData[currentPixelInData] = sum1;
destData[currentPixelInData+1] = sum2;
destData[currentPixelInData+2] = sum3;
destData[currentPixelInData+3] = sum4;
}
}
//Blur vertically
for (int row = 0; row < imageHeight; row++) {
for (int column = 0; column < imageWidth; column++) {
int currentPixel = (row*imageWidth)+column;
int sum1 = 0;
int sum2 = 0;
int sum3 = 0;
int sum4 = 0;
int index = 0;
for (int offset = -radius; offset <= radius; offset++) {
if (!(row+offset < 0) && !(row+offset > imageHeight-1)) {
int firstByteOfPixelWereLookingAtInSrcData = (currentPixel+(offset*imageWidth))*4;
int in1 = destData[firstByteOfPixelWereLookingAtInSrcData];
int in2 = destData[firstByteOfPixelWereLookingAtInSrcData+1];
int in3 = destData[firstByteOfPixelWereLookingAtInSrcData+2];
int in4 = destData[firstByteOfPixelWereLookingAtInSrcData+3];
sum1 += (int)(in1 * kernel[index]);
sum2 += (int)(in2 * kernel[index]);
sum3 += (int)(in3 * kernel[index]);
sum4 += (int)(in4 * kernel[index]);
}
index++;
}
int currentPixelInData = currentPixel*4;
finalData[currentPixelInData] = sum1;
finalData[currentPixelInData+1] = sum2;
finalData[currentPixelInData+2] = sum3;
finalData[currentPixelInData+3] = sum4;
}
}
To reverse engineer a filter, you need to find its impulse response. On a background of a very dark value, say 32, place a nearly white pixel, say 223. You don't want to use 0 and 255 because some filters will try to create values beyond the starting values. Run the filter on this image, and take the output values and stretch them from 0.0 to 1.0: (value-32)/(223-32). Now you have the exact weights needed to emulate the filter.
There are lots of ways to treat the image edges. I would suggest taking the filter weights and summing them, then dividing the result by that sum; if you're trying to go beyond the edge, use 0.0 for both the pixel value and the filter weight on that pixel.
Boundary conditions sometimes depend on exactly what you're doing and what kind of data you're working with, but I think for general purpose image manipulation the best thing to do is to extend the values at the borders beyond the edges of the image. Not literally of course, but if the filter tries to read a pixel that's outside the image borders, you substitute the value of the nearest pixel on the edge of the image. Which is really the same as just clamping the row to be between 0 and height, and the column to be between 0 and width.
Related
I tried to code histogram equalization operation in order to enhance contrast of the images, but my code didn't work. When I displayed image's original histogram and histogram after processed by my code I saw that output histogram only have a value at 0 and there aren't values for other pixel intensities. I don't know why. Here is my code:
private: System::Void histogramEqualizationToolStripMenuItem_Click(System::Object^ sender, System::EventArgs^ e) {
Raw_Intensity = ConvertBMPToIntensity(Buffer, Width, Height);
int histogram[256] = { 0 };
int equalizedHistogram[256] = { 0 };
int runningSum = 0;
int numberOfPixels = Width * Height;
for (int row = 0; row < Height; row++)
{
for (int column = 0; column < Width; column++)
{
histogram[Raw_Intensity[row * Width + column]]++;
}
}
for (int i = 0; i < 256; i++)
{
runningSum += histogram[i];
int index = round(((runningSum / numberOfPixels) * 255));
equalizedHistogram[index] += histogram[i];
}
}
I think the casting issue is occuring.
change this line :
int index = round(((runningSum / numberOfPixels) * 255));
to
int index = round(((runningSum*1.0 / numberOfPixels) * 255));
How to efficiency linearized Mat (symmetric matrix) to one row by right triangle.
For example, when I have:
0aabbb
b0aaaa
ba0bba
bac0aa
aaaa0c
abcab0
and then from that I get:
aabbbaaaabbaaac
Something like this:
...
template<class T>
Mat SSMJ::triangleLinearized(Mat mat){
int c = mat.cols;
Mat row = Mat(1, ((c*c)-c)/2, mat.type());
int i = 0;
for(int y = 1; y < mat.rows; y++)
for(int x = y; x < mat.cols; x++) {
row.at<T>(i)=mat.at<T>(y, x);
i++;
}
return row;
}
...
Since data in your mat is just a 1d array stored in row.data you can do whatever you want with it. I don't think you will find anything more special (w/o using vectorized methods) than just copying from this array.
int rows = 6;
char data[] = { 0,1,2,3,4,5,
0,1,2,3,4,5,
0,1,2,3,4,5,
0,1,2,3,4,5,
0,1,2,3,4,5};
char result[100];
int offset = 0;
for (int i = 0; i < 5; offset += 5-i, i++) {
memcpy(&result[offset] , &data[rows * i + i + 1], 5 - i);
}
Or with opencv Mat it would be
int rows = mat.cols;
char result[100]; // you can calculate how much data u need
int offset = 0;
for (int i = 0; i < 5; offset += 5-i, i++) {
memcpy(&result[offset] , &mat.data[rows * i + i + 1], 5 - i);
}
Mat resultMat(1, offset, result);
I am trying to understand the LASSO algorithm for linear regression. I have implemented the algorithm using naive coordinate descent method for optimization. However the coefficients that I obtained from my code, wasn't matching with those obtained from the 'glmnet'package for LASSO in R. I wanted to understand how I could make the algorithm more accurate, so that the coefficients match with those obtained from R. I think they use coordinate descent as well.
Note: I have generated some toy data with 11 observations, and 6
features(x,x^2 ,x^3,...,x^6). The last column contains the y values
generated from a dummy function (e^(-x^2)). I wanted to use LASSO to
estimate this function. Also, I have randomly picked the initial
weight vector, multiple times to crosscheck my results.
Here is my code:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<time.h>
int num_dim = 6;
int num_obs = 11;
/*Computes the normalization factor*/
float norm_feature(int j,double arr[][7],int n){
float sum = 0.0;
int i;
for(i=0;i<n;i++){
sum = sum + pow(arr[i][j],2);
}
return sum;
}
/*Computes the partial sum*/
float approx(int dim,int d_ignore,float weights[],double arr[][7],int
i){
int flag = 1;
if(d_ignore == -1)
flag = 0;
int j;
float sum = 0.0;
for(j=0;j<dim;j++){
if(j != d_ignore)
sum = sum + weights[j]*arr[i][j];
else
continue;
}
return sum;
}
/* Computes rho-j */
float rho_j(double arr[][7],int n,int j,float weights[7]){
float sum = 0.0;
int i;
float partial_sum ;
for(i=0;i<n;i++){
partial_sum = approx(num_dim,j,weights,arr,i);
sum = sum + arr[i][j]*(arr[i][num_dim]-partial_sum);
}
return sum;
}
float intercept(float arr1[7],double arr[][7],int dim) {
int i;
float sum =0.0;
for (i = 0; i < num_obs; i++) {
sum = sum + pow((arr[i][num_dim]) - approx(num_dim, -1, arr1, arr,
i), 1);
}
return sum;
}
int main(){
double data[num_obs][7];
int i=0,j=0;
float a = 1.0;
float lambda = 0.1; //Setting lambda
float weights[7]; //weights[6] contains the intercept
srand((unsigned int) time(NULL));
/*Generating the data matrix */
for(i=0;i<11;i++)
data[i][0] = ((float)rand()/(float)(RAND_MAX)) * a;
for(i=0;i<11;i++)
for(j=1;j<6;j++)
data[i][j] = pow(data[i][0],j+1);
for(i=0;i<11;i++)
data[i][6] = exp(-pow(data[i][0],2)); // the last column in the
datamatrix contains the y values generated by the dummy function
/*Printing the data matrix */
printf("Data Matrix:\n");
for(i=0;i<11;i++){
for(j=0;j<7;j++){
printf("%lf ",data[i][j]);}
printf("\n");}
printf("\n");
int seed =0;
while(seed<20) {
//Initializing the weight vector
for (i = 0; i < 7; i++)
weights[i] = ((float) rand() / (float) (RAND_MAX)) * a;
int iter = 500;
int t = 0;
int r, l;
double rho[num_dim];
for (i = 0; i < 6; i++) {
rho[i] = rho_j(data, num_obs, r, weights);
}
// Intercept initialization
weights[num_dim] = intercept(weights,data,num_dim);
printf("Weights initialization: ");
for (i = 0; i < (num_dim+1); i++)
printf("%f ", weights[i]);
printf("\n");
while (t < iter) {
for (r = 0; r < num_dim; r++) {
rho[r] = rho_j(data, num_obs, r, weights);
//printf("rho %d:%f ",r,rho[r]);
if (rho[r] < -lambda / 2)
weights[r] = (rho[r] + lambda / 2) / norm_feature(r,
data, num_obs);
else if (rho[r] > lambda / 2)
weights[r] = (rho[r] - lambda / 2) / norm_feature(r,
data, num_obs);
else
weights[r] = 0;
weights[num_dim] = intercept(weights, data, num_dim);
}
/* printf("Iter(%d): ", t);
for (l = 0; l < 7; l++)
printf("%f ", weights[l]);
printf("\n");*/
t++;
}
//printf("\n");
printf("Final Weights: ");
for (i = 0; i < 7; i++)
printf("%f ", weights[i]);
printf("\n");
printf("\n");
seed++;
}
return 0;
}
PseudoCode:
I'm trying to group similar hues together using a given threshold. It works quite well except for red values. Since near 0 or 180 represent red in OpenCV, I'm having trouble to group let say 3 degree and 179 degree hues in the same group.
The hues are stored in a Vector.
I have created a function with the following signature.
Vector <uchar> getGroupedHues(Vector<uchar> hues, int threshold);
The final goal is to create a smarties counter. I have isolated the individual smarties and now I want to find the hue of each one to classified them.
I based my code using the page. The algorithm to cluster the hues is at the end, but like I said, I'm struggling with near 0/180 degrees values.
Thanks for helping!
UPDATE
This is the code I have made.
// Creates a cluster of hues that are within a threshold
Vector<uchar> getClusteredHues(Vector<uchar> values, int threshold) {
int nbBin = 180;
Vector <uchar> groups(nbBin, 0);
// Sorting the hues
sort(values.begin(), values.end());
Point2f previous = getPointFromAngle(values[0]);
Point2f currentCluster = previous;
Point2f currentValue;
Point2f delta;
Point2f thresholdXY = getPointFromAngle(threshold);
groups[values[0]]++;
for (int i = 1; i < values.size(); i++) {
currentValue = getPointFromAngle( values[i]);
delta = currentValue - previous;
if (delta.x < thresholdXY.x && delta.y < thresholdXY.y) {
groups[(int)(atan2(currentCluster.y, currentCluster.x)* 180 / CV_PI)]++;
}
else {
currentCluster = currentValue;
groups[(int)(atan2(currentCluster.y, currentCluster.x)* 180 / CV_PI)]++;
}
previous = currentValue;
}
return groups;
}
Ok, I have found a workaround. I always check if the current value is near the end limit, if so, I the current group becomes the first group.
Here's is the code.
Vector<uchar> getClusteredHues(Vector<uchar> values, int threshold) {
int nbBin = 180;
Vector <uchar> clusters(nbBin, 0);
// trier les teintes
sort(values.begin(), values.end());
int previous = values[0];
int currentCluster = previous;
int currentValue;
int delta;
int halfThreshold = threshold / 2;
int firstCluster = values[0];
clusters[values[0]]++;
for (int i = 1; i < values.size(); i++) {
currentValue = values[i];
delta = currentValue - previous;
if (currentValue + threshold > nbBin) {
if (abs(firstCluster - (currentValue + threshold - nbBin)) < threshold) {
delta = 0;
currentCluster = firstCluster;
}
}
if (delta < threshold) {
clusters[currentCluster]++;
}
else {
currentCluster = currentValue;
clusters[currentCluster]++;
}
previous = currentValue;
}
return clusters;
}
I am wondering how to actually sample the data I am passing to the shader file. I am using two methods, is it the same for both? Are there any resources online for me to actually read up on this sort of thing?
Compiling at 5.0 but the version number does not matter so much.
I have two methods to pass the data.
The first;
for( UINT row = 0; row < textureDesc.Height; row++ )
{
UINT rowStart = row * mappedResource.RowPitch;
for( UINT col = 0; col < textureDesc.Width; col++ )
{
//width * number of channels (r,g,b,a)
UINT colStart = col * 4;
pTexels[rowStart + colStart + 0] = 10.0f; // Red
pTexels[rowStart + colStart + 1] = 10.0f; // Green
pTexels[rowStart + colStart + 2] = 255.0f; // Blue
pTexels[rowStart + colStart + 3] = 255.0f; // Alpha
}
}
The second;
float elements[416][416];
int elementsCount = 416*416;
for( int i = 0; i < 416; i++ )
{
for( int k = 0; k < 416; k++ )
{
elements[i][k] = 0;
}
}
memcpy(mappedResource.pData, elements, sizeof(float) * elementsCount);
Seems that I missed an important part of all of this.
When creating a texture, in the texture description, the Format is the type that will be returned when the object is sampled. Many thanks to Drop for the help.