I tried to make a gaussian blur operation using c + + (OpenCV).
This is the code
int mask [3][3] = {1 ,2 ,1 ,
2 ,3 ,2 ,
1 ,2 ,1 };
int getPixel ( unsigned char * arr , int col , int row ) {
int sum = 0;
for ( int j = -1; j <=1; j ++) {
for ( int i = -1; i <=1; i ++) {
int color = arr [( row + j ) * width + ( col + i ) ];
sum += color * mask [ i +1][ j +1];
}
}
return sum /15;
}
void h_blur ( unsigned char * arr , unsigned char * result) {
int offset = 2 *width ;
for ( int row =2; row < height -3; row ++) {
for ( int col =2; col < width -3; col ++) {
result [ offset + col ] = getPixel ( arr , col , row ) ;
}
offset += width ;
}
}
int main(int argc, char** argv)
{
starttime = getTickCount();
image_input = cvLoadImage("test.jpg", CV_LOAD_IMAGE_UNCHANGED);
width = image_input->width;
height = image_input->height;
widthStep = image_input->widthStep;
channels = image_input->nChannels;
IplImage* image_output = cvCreateImage(cvGetSize(image_input),IPL_DEPTH_8U,channels);
unsigned char *h_out = (unsigned char*)image_output->imageData;
unsigned char *h_in = (unsigned char*)image_input->imageData;
//sobel_parallel(h_in, h_out, width, height, widthStep, channels);
h_blur ( h_in , h_out) ;
endtime = getTickCount();
printf("Waktu Eksekusi = %f\n", (endtime-starttime)/getTickFrequency());
cvShowImage("CPU", image_output);
cvSaveImage("output.jpg",image_output);
cvReleaseImage(&image_output);
waitKey(0);
}
but when i run the program, the image are divided into three. I still have not found what is wrong with my code. T_T
here the result
please help me solve this problem.
#include <opencv2/opencv.hpp>
int mask [3][3] = {1 ,2 ,1 ,
2 ,3 ,2 ,
1 ,2 ,1 };
int width;
int height;
int widthStep;
int channels;
int getPixel ( unsigned char * arr , int col , int row , int k ) {
int sum = 0;
int denom = 0;
for ( int j = -1; j <=1; j ++) {
for ( int i = -1; i <=1; i ++) {
if ((row + j) >= 0 && (row + j) < height && (col + i) >= 0 && (col + i) < width) {
int color = arr [( row + j ) * 3 * width + ( col + i ) * 3 + k];
sum += color * mask [ i +1][ j +1];
denom += mask [ i +1][ j +1];
}
}
}
return sum / denom;
}
void h_blur ( unsigned char * arr , unsigned char * result) {
for ( int row =0; row < height; row ++) {
for ( int col =0; col < width; col ++) {
for (int k = 0; k < 3; k++) {
result [ 3 * row * width + 3 * col + k] = getPixel ( arr , col , row , k ) ;
}
}
}
}
int main(int argc, char** argv)
{
//starttime = getTickCount();
IplImage *image_input = cvLoadImage("test.jpg", CV_LOAD_IMAGE_UNCHANGED);
width = image_input->width;
height = image_input->height;
widthStep = image_input->widthStep;
channels = image_input->nChannels;
IplImage* image_output = cvCreateImage(cvGetSize(image_input),IPL_DEPTH_8U,channels);
unsigned char *h_out = (unsigned char*)image_output->imageData;
unsigned char *h_in = (unsigned char*)image_input->imageData;
//sobel_parallel(h_in, h_out, width, height, widthStep, channels);
h_blur ( h_in , h_out) ;
//endtime = getTickCount();
//printf("Waktu Eksekusi = %f\n", (endtime-starttime)/getTickFrequency());
cvShowImage("input", image_input);
cvShowImage("CPU", image_output);
cvSaveImage("output.jpg",image_output);
cvReleaseImage(&image_output);
cv::waitKey(0);
}
I had a few minor issues when compiling your code, so there are a few extra changes (it seems like the top section of your code may have been cut off, so a few variable declarations are missing).
In any case, the big changes are to getPixel and h_blur.
The main problem in your code was that you did not handle the fact that the data contains three bytes (blue, green, red) for each pixel, not one byte. Because of this, your code only actually looked at the first third of the image, and it swapped around the colors a bit.
Related
I need to translate GaussianFilter that uses openCV to code that uses BMP image ( so i first read image, and translate it to greyscale). My function using openCV looks like ( basic GaussianFilter ) :
Mat CreateGaussFilter(int kernalHeight, int kernalWidth, double kernalArray[5][5]){
Mat image = imread("konik.jpg");
Mat grayScaleImage(image.size(),CV_8UC1);
Mat filter(image.size(),CV_8UC1);
cvtColor(image,grayScaleImage,CV_RGB2GRAY);
int rows=image.rows;
int cols=image.cols;
int verticleImageBound=(kernalHeight-1)/2;
int horizontalImageBound=(kernalWidth-1)/2;
for(int row=0+verticleImageBound;row<rows-verticleImageBound;row++){
for(int col=0+horizontalImageBound;col<cols-horizontalImageBound;col++){
float value=0.0;
for(int kRow=0;kRow<kernalHeight;kRow++){
for(int kCol=0;kCol<kernalWidth;kCol++){
float pixel=grayScaleImage.at<uchar>(kRow+row-verticleImageBound,kCol+col-horizontalImageBound)*kernalArray[kRow][kCol];
value+=pixel;
}
}
filter.at<uchar>(row,col)=cvRound(value);
}
}
return filter;
}
Now for BMP image:
i have loaded it using:
struct Info{
int width;
int height;
int offset;
unsigned char * info;
unsigned char * data;
int size;
};
Info readBMP(char* filename)
{
int i;
std::ifstream is(filename, std::ifstream::binary);
is.seekg(0, is.end);
i = is.tellg();
is.seekg(0);
unsigned char *info = new unsigned char[i];
is.read((char *)info,i);
int width = *(int*)&info[18];
int height = *(int*)&info[22];
int offset = *(int*)&info[10];
unsigned char a[offset];
unsigned char *b = new unsigned char[i - offset];
std::copy(info,
info + offset,
a);
std::copy(info + offset,
info + i,
b + 0);
Info dat;
dat.width = width;
dat.height = height;
dat.offset = offset;
dat.size = i;
dat.info = new unsigned char[offset - 1];
dat.data = new unsigned char[i - offset + 1];
for( int j = 0; j < offset ; j++ ){
dat.info[j] = a[j];
}
for( int j = 0; j < i - offset; j++ ){
dat.data[j] = b[j];
}
return dat;
}
turned it into grayscale usin:
void greyScale( unsigned char * src , int rows, int cols){
for( int i = 0; i < rows; i++){
for( int j = 0; j < cols; j++){
unsigned char r = src[3 * (i * cols + j)];
unsigned char g = src[3 * (i * cols + j) + 1];
unsigned char b = src[3 * (i * cols + j) + 2];
char linearIntensity = (char)(0.2126f * r + 0.7512f * g + 0);
src[3 * (i * cols + j)] = linearIntensity;
src[3 * (i * cols + j) + 1] = linearIntensity;
src[3 * (i * cols + j) + 2] = linearIntensity;
}
}
}
And now i am trying to use GaussianFilter ( translated from my OpenCV function )
void FilterCreation(double GKernel[][5]) {
// intialising standard deviation to 1.0
double sigma = 1.0;
double r, s = 2.0 * sigma * sigma;
// sum is for normalization
double sum = 0.0;
// generating 5x5 kernel
for (int x = -2; x <= 2; x++) {
for (int y = -2; y <= 2; y++) {
r = sqrt(x * x + y * y);
GKernel[x + 2][y + 2] = (exp(-(r * r) / s)) / (M_PI * s);
sum += GKernel[x + 2][y + 2];
}
}
// normalising the Kernel
for (int i = 0; i < 5; ++i)
for (int j = 0; j < 5; ++j)
GKernel[i][j] /= sum;
}
unsigned char ** CreateGaussFilter(unsigned char ** src,int kernalHeight, int kernalWidth, double kernalArray[5][5], int rows, int cols){
int verticleImageBound=(kernalHeight-1)/2;
int horizontalImageBound=(kernalWidth-1)/2;
unsigned char ** dst = new unsigned char *[rows];
for( int i = 0; i < rows; i++){
dst[i] = new unsigned char [cols];
}
for(int row=0+verticleImageBound;row<rows-verticleImageBound;row++){
for(int col=0+horizontalImageBound;col<cols-horizontalImageBound;col++){
float value=0;
for(int kRow=0;kRow<kernalHeight;kRow++){
for(int kCol=0;kCol<kernalWidth;kCol++){
float pixel =src[kRow+row-verticleImageBound][kCol+col-horizontalImageBound]*kernalArray[kRow][kCol];
value+=pixel;
}
}
dst[row][col] = round(value);
}
}
return dst;
}
Since grayscale values are same for every channel, istead of doing calculation like in grayscale function, i turned the data into 2d array and then back into 1d array using:
unsigned char ** return2darray(unsigned char *src, int width, int height, int size){
unsigned char **array = new unsigned char *[width];
for( int i = 0; i < width; i++ ){
array[i] = new unsigned char[height];
}
for( int i = 0; i < width; i++ ){
for( int j = 0; j < height; j++ ){
array[i][j] = src[3 * (i * height + j)];
}
}
return array;
}
unsigned char * return1darray(unsigned char **src, int width, int height, int size){
unsigned char *array = new unsigned char[size];
for( int i = 0; i < width; i++ ){
for( int j = 0; j < height; j++ ){
array[3 * (i * height + j)] = src[i][j];
array[3 * (i * height + j) + 1] = src[i][j];
array[3 * (i * height + j) + 2] = src[i][j];
}
}
return array;
}
And using it like:
int main() {
// load img
Info dat = readBMP("input.bmp");
// turn in into greyscale
greyScale(dat.data,dat.width,dat.height);
// turn 1d array into 2d
unsigned char** arr = return2darray(dat.data,dat.width,dat.height,dat.size);
double GKernel[5][5];
// geneate gausian filter
FilterCreation(GKernel);
// apply gausianFilter
unsigned char** filter = CreateGaussFilter(arr,5,5,GKernel,dat.width,dat.height,dat.size);
// convert it back into 1d array
unsigned char* ar = return1darray(filter,dat.width,dat.height,dat.size);
ofstream fout;
fout.open("out.bmp", ios::binary | ios::out);
fout.write( reinterpret_cast<char *>(dat.info), dat.offset);
fout.write( reinterpret_cast<char *>(ar), dat.size - dat.offset );
fout.close();
return 0;
}
But for some reason, that I cannot realize for input :
the output looks like this.
It seems like it reads the same values in periodes, but that would mean the original image would have the same periods because it just reads bytes from loaded image. The GreyScale function works as it should. I am not very proficient in manipulation with images ( i was using openCV all the time ) What could cause these periods? Thanks for the help!
I am doing a small project in image processing using CUDA.I am trying to use Gaussian blurring to blur an image.Everything is fine but I cannot figure out why the kernel launch statement is showing this strange error:
Here is my complete code, if it can be of any help:
#include<time.h>
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<cuda_runtime.h>
#include<device_launch_parameters.h>
#include <helper_cuda.h>
#include <helper_cuda_gl.h>
#include<helper_image.h>
#include< helper_cuda_gl.h>
#include<helper_cuda_drvapi.h>
unsigned int width, height;
int mask[3][3] = { 1, 2, 1,
2, 3, 2,
1, 2, 1,
};
int getPixel(unsigned char *arr, int col, int row)
{
int sum = 0;
for (int j = -1; j <= 1; j++)
{
for (int i = -1; i <= 1; i++)
{
int color = arr[(row + j)*width + (col + i)];
sum += color*mask[i + 1][j + 1];
}
}
return sum / 15;
}
void h_blur(unsigned char * arr, unsigned char * result){
int offset = 2 * width;
for (int row = 2; row < height - 3; row++)
{
for (int col = 2; col < width - 3; col++)
{
result[offset + col] = getPixel(arr, col, row);
}
offset += width;
}
}
__global__ void d_blur(unsigned char *arr, unsigned char * result, int width, int height)
{
int col = blockIdx.x*blockDim.x + threadIdx.x;
int row = blockIdx.y*blockDim.y + threadIdx.y;
if (row < 2 || col < 2 || row >= height - 3 || col >= width - 3)
return;
int mask[3][3] = { 1, 2, 1, 2, 3, 2, 1, 2, 1 };
int sum = 0;
for (int j = -1; j <= 1; j++)
{
int color = arr[(row + j)*width + (col + i)];
sum += color*mask[i + 1][j + 1];
}
result[row*width + col] = sum / 15;
}
int main(int argc, char ** argv)
{
unsigned char *d_resultPixels;
unsigned char *h_resultPixels;
unsigned char *h_pixels = NULL;
unsigned char *d_pixels = NULL;
char *srcPath = "C:\ProgramData\NVIDIA Corporation\CUDA Samples\v6.5\3_Imaging\dxtc\data\lena_std.ppm";
char *h_ResultPath = "C:\ProgramData\NVIDIA Corporation\CUDA Samples\v6.5\3_Imaging\dxtc\data\lena_std.ppm";
char *d_ResultPath = "C:\ProgramData\NVIDIA Corporation\CUDA Samples\v6.5\3_Imaging\dxtc\data\lena_std.ppm";
sdkLoadPGM(srcPath, &h_pixels, &width, &height);
int ImageSize = sizeof(unsigned char) * width * height;
h_resultPixels = (unsigned char *)malloc(ImageSize);
cudaMalloc((void**)&d_pixels, ImageSize);
cudaMalloc((void**)&d_resultPixels, ImageSize);
cudaMemcpy(d_pixels, h_pixels, ImageSize, cudaMemcpyHostToDevice);
dim3 block(16, 16);
dim3 grid(width / 16, height / 16);
d_blur << < grid, block >> >(d_pixels, d_resultPixels, width, height);
cudaThreadSynchronize();
cudaMemcpy(h_resultPixels, d_resultPixels, ImageSize, cudaMemcpyDeviceToHost);
sdkSavePGM(d_ResultPath, h_resultPixels, width, height);
printf("Press enter to exit ...\n");
getchar();
}
As you are trying to run this in Visual Studio, you need to update the Intellisense. Also,you can refer the following link for a better Image Convolution Operation in CUDA.
2D Image Convolution in CUDA
Below screen shot is the result of the execution of the function in MATLAB.
a=imread('C:\CVIPtools\images\car.bmp');
ad=im2double(a);
ht = halftoneCVIP(ad,4,255, 0.5, 0, 0);
Halftoning: it's a methods for reducing the number of gray levels by creating dot patterns or dither patterns to represent various gray levels, reduces effective spatial resolution also.
There are 6 methods in halftoning.
1. Floyd Stienberg
2. Dither
3. Threshold
4. Cluster 3
5. Cluster 4
6. Cluster 8
*Image *CVIPhalftone(Image cvip_Image, int halftone, int
maxval, float fthreshval, CVIP_BOOLEAN retain_image,
CVIP_BOOLEAN verbose)
<cvip_Image> - pointer to input image
<halftone> - indicates method used to convert from grays-
cale to binary. (one of QT_FS, QT_THRESH, QT_DITHER8,
QT_CLUSTER3, QT_CLUSTER4, QT_CLUSTER8)
<maxval> - specifies maximum range of input image (usually
255)
<fthreshval> - threshold value (for QT_THRESH) between [0.0
... 1.0].
<retain_image> - retain image after writing (CVIP_YES or
CVIP_NO)?
<verbose> - shall I be verbose (CVIP_YES or CVIP_NO)?**
I am trying to reuse a halftone function origianlly written in C. My objective is to make this function executable in MATLAB by writing a wrapper function using MEX.
Below are the code I have written and I am able to compile successfully without any errors. However, while executing the function MATLAB crashes. Does anyone know the reason behind this?
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include "mex.h"
#include "CVIPtools.h"
#include "CVIPimage.h"
#include "CVIPdef.h"
#include "CVIPmap.h"
#include "limits.h"
#include "threshold.h"
#include <float.h>
#include "CVIPmatrix.h"
#include "dithers.h"
#include "CVIPhalftone.h"
#define CVIP_WHITE 1
#define CVIP_BLACK 0
#define FS_SCALE 1024
#define HALF_FS_SCALE 512
Image *CVIPhalftone(Image *cvip_Image, int halftone, int maxval, float fthreshval, CVIP_BOOLEAN retain_image, CVIP_BOOLEAN verbose)
{
byte* grayrow;
register byte* gP;
byte* bitrow;
register byte* bP;
int rows, cols, row;
int col, limitcol, format;
char function_name[] = {"CVIPhalftone"};
long threshval, sum;
long* thiserr;
long* nexterr;
long* temperr;
int fs_direction;
Image *bit_Image;
cols = cvip_Image->image_ptr[0]->cols;
rows = cvip_Image->image_ptr[0]->rows;
bit_Image = (Image *) image_allocate(cvip_Image->image_format, BINARY, 1, rows, cols, CVIP_BYTE, REAL);
format = cvip_Image->image_format;
if( !(format==PBM || format==PGM || format==TIF || format==RAS || format==BIN || format==ITX) ) {
if(verbose)
fprintf(stderr, "\n%s: casting image to format that supports binary images - (PBM).\n",function_name);
bit_Image->image_format = PBM;
}
mexPrintf("Till here 1\n");
/* Initialize. */
switch ( halftone )
{
case QT_FS: // QT_FS=1 defined in CVIPhalftone.h
if(verbose)
fprintf(stderr, "%s: performing boustrophedonic Floyd-Steinberg error diffusion.\n\n",function_name);
/* Initialize Floyd-Steinberg error vectors. */
thiserr = (long*) calloc( cols + 2, sizeof(long) );
nexterr = (long*) calloc( cols + 2, sizeof(long) );
srand( (int) ( time( 0 ) ^ getpid( ) ) );
for ( col = 0; col < cols + 2; ++col )
thiserr[col] = ( rand( ) % FS_SCALE - HALF_FS_SCALE ) / 4;
/* (random errors in [-FS_SCALE/8 .. FS_SCALE/8]) */
fs_direction = 1;
threshval = fthreshval * FS_SCALE;
break;
case QT_THRESH: // QT_THRESH=2 defined in CVIPhalftone.h
threshval = fthreshval * maxval + 0.999999;
if(verbose) {
fprintf(stderr, "%s: performing simple thresholding operation.\n",function_name);
fprintf(stderr, "%s: threshold level - %ld.\n\n",function_name, threshval);
}
break;
case QT_DITHER8: // QT_DITHER8=3 defined in CVIPhalftone.h
break;
case QT_CLUSTER3: // QT_CLUSTER3=4 defined in CVIPhalftone.h
break;
case QT_CLUSTER4: // QT_CLUSTER4=5 defined in CVIPhalftone.h
break;
case QT_CLUSTER8: // QT_CLUSTER8=6 defined in CVIPhalftone.h
break;
default:
fprintf(stderr, "%s: can't happen... but apparently something did?!?\n" , function_name); break;
}
mexPrintf("Till here 2\n");
for ( row = 0; row < rows; ++row )
{
grayrow = (byte *) ((byte **) cvip_Image->image_ptr[0]->rptr)[row];
bitrow = (byte *) ((byte **) bit_Image->image_ptr[0]->rptr)[row];
switch ( halftone )
{
case QT_FS:
for ( col = 0; col < cols + 2; ++col )
nexterr[col] = 0;
if ( fs_direction )
{
col = 0;
limitcol = cols;
gP = grayrow;
bP = bitrow;
}
else
{
col = cols - 1;
limitcol = -1;
gP = &(grayrow[col]);
bP = &(bitrow[col]);
}
do
{
sum = ( (long) *gP * FS_SCALE ) / maxval + thiserr[col + 1];
if ( sum >= threshval )
{
*bP = CVIP_WHITE;
sum = sum - threshval - HALF_FS_SCALE;
}
else
*bP = CVIP_BLACK;
if ( fs_direction )
{
thiserr[col + 2] += ( sum * 7 ) / 16;
nexterr[col ] += ( sum * 3 ) / 16;
nexterr[col + 1] += ( sum * 5 ) / 16;
nexterr[col + 2] += ( sum ) / 16;
++col;
++gP;
++bP;
}
else
{
thiserr[col ] += ( sum * 7 ) / 16;
nexterr[col + 2] += ( sum * 3 ) / 16;
nexterr[col + 1] += ( sum * 5 ) / 16;
nexterr[col ] += ( sum ) / 16;
--col;
--gP;
--bP;
}
}
while ( col != limitcol );
temperr = thiserr;
thiserr = nexterr;
nexterr = temperr;
fs_direction = ! fs_direction;
break;
case QT_THRESH:
for ( col = 0, gP = grayrow, bP = bitrow; col < cols; ++col, ++gP, ++bP )
if ( *gP >= threshval )
*bP = CVIP_WHITE;
else
*bP = CVIP_BLACK;
break;
case QT_DITHER8:
for ( col = 0, gP = grayrow, bP = bitrow; col < cols; ++col, ++gP, ++bP )
if ( *gP >= dither8[row % 16][col % 16] * ( maxval + 1 ) / 256 )
*bP = CVIP_WHITE;
else
*bP = CVIP_BLACK;
break;
case QT_CLUSTER3:
for ( col = 0, gP = grayrow, bP = bitrow; col < cols; ++col, ++gP, ++bP )
if ( *gP >= cluster3[row %6][col %6 ] * ( maxval + 1 ) / 18 )
*bP = CVIP_WHITE;
else
*bP = CVIP_BLACK;
break;
case QT_CLUSTER4:
for ( col = 0, gP = grayrow, bP = bitrow; col < cols; ++col, ++gP, ++bP )
if ( *gP >= cluster4[row %8][col%8] * ( maxval + 1 ) / 32 )
*bP = CVIP_WHITE;
else
*bP = CVIP_BLACK;
break;
case QT_CLUSTER8:
for ( col = 0, gP = grayrow, bP = bitrow; col < cols; ++col, ++gP, ++bP )
if ( *gP >= cluster8[row %16][col %16] * ( maxval + 1 ) / 128 )
*bP = CVIP_WHITE;
else
*bP = CVIP_BLACK;
break;
default:
fprintf(stderr, "%s: can't happen... but apparently something did?!?\n" , function_name); break;
}
}
mexPrintf("Till here 1\n");
if(!retain_image)
image_free(cvip_Image);
return bit_Image;
mexPrintf("Till here 2\n");
}
void midd( int choice, double *indata, double *outdata, int n, int row, int col, int bands)
{
Image *inputImage;
byte **image;
unsigned int r, c;
int i;
unsigned int no_of_rows,
no_of_cols,
no_of_bands;
COLOR_FORMAT color_space;
int check=0;
no_of_bands = bands;
no_of_rows = row;
no_of_cols = col;
for (i=0;i<n;i++)
{ if (check<indata[i])
check=indata[i];
}
if (check<=1){
for (i=0;i<n;i++){
//outdata[i]= floor(255*indata[i]); //By Krishna Regmi
indata[i]= floor(255*indata[i]);
}}
else
{for (i=0;i<n;i++)
//outdata[i]= floor(indata[i]); //By Krishna Regmi
indata[i]= floor(indata[i]);
}
// mexPrintf("\ first value after scaling to 0-255 %f\n", outdata[0]);
// typedef enum {PBM, PGM, PPM, EPS, TIF, GIF, RAS, ITX, IRIS, CCC, BIN, VIP, GLR, BTC, BRC, HUF, ZVL, ARITH, BTC2, BTC3, DPC, ZON, ZON2, SAFVR, JPG, WVQ, FRA, VQ, XVQ} IMAGE_FORMAT;
//typedef enum {BINARY, GRAY_SCALE, RGB, HSL, HSV, SCT, CCT, LUV, LAB, XYZ}
inputImage=new_Image (BMP, RGB, no_of_bands, row, col, CVIP_BYTE, REAL );
for(bands=0; bands < no_of_bands; bands++) {
image = getData_Image(inputImage, bands);
for(r=0; r < no_of_rows; r++) {
for(c=0; c < no_of_cols; c++)
{
image[r][c]=outdata[r+row*c+row*col*bands]; /* passing data from MATLAB variable to CVIPtools variable */
}
}
}
//Image *CVIPhalftone(Image *cvip_Image, int halftone, int maxval, float fthreshval, CVIP_BOOLEAN retain_image, CVIP_BOOLEAN verbose)
//inputImage= CVIPhalftone(cvipImage,QT_THRESH,255,0.5,CVIP_NO,CVIP_NO);
inputImage = CVIPhalftone(inputImage, choice, 255, 0.5, CVIP_NO, CVIP_NO);
for(bands=0; bands < no_of_bands; bands++) {
image = getData_Image(inputImage, bands);
for(r=0; r < no_of_rows; r++) {
for(c=0; c < no_of_cols; c++)
{
outdata[r+row*c+row*col*bands] = floor(image[r][c]); /* passing data back to MATLAB variable from CVIPtools variable */
}
}
}
} /* end of wrapper function*/
/* main gateway function*/
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
double *outdata, *indata;
int r,c,bands;
const mwSize *dim_array;
int choice,n;
//char color_type;
// COLOR_FORMAT color_space;
//int choice;
//int n = mxGetNumberOfElements(prhs[0]);
n = mxGetNumberOfElements(prhs[0]);
indata = mxGetData(prhs[0]);
//double *indata = (double *)mxGetData(prhs[0]);
dim_array = mxGetDimensions(prhs[0]);
//color_type = mxGetChars(prhs[1]);
choice = mxGetScalar(prhs[1]);
r = dim_array[0];
c = dim_array[1];
bands = dim_array[2];
// mexPrintf("total elements %d\n", n);
if(bands==3){
plhs[0] = mxCreateNumericArray(3, dim_array, mxDOUBLE_CLASS, mxREAL);
}
else
{ plhs[0] = mxCreateDoubleMatrix(r,c,mxREAL);
bands=1;
}
outdata = mxGetData(plhs[0]);
midd(choice, indata, outdata, n, r, c, bands);
}
Sounds like a segmentation fault in your mex code. Check the input datatypes. Make sure that the data type of the parameters passed from matlab match those that are expected by the C function. Also, keep in mind that matlab arrays are column-major, and the sizes are [rows, cols], not [width height].
If you can't spot the problem easily, then you would need to attach a debugger to the matlab process, or add a lot of mexPrintf's into your code to see where exactly it fails.
I want to implement ,as possible , spdiags function in C.
(I prefer C to C++ and I don't want to use C++ algorithms for now)
Having as input matrix:
inMx =
1 0 0
4 5 6
0 7 9
you should obtain (running that using spdiags in Matlab) :
ouMx =
4 1 0
7 5 0
0 9 6
(one thing I can't understand though , is even though at the documentation it says that zeros are inserted at the top if you are below the main diagonal , here you we can see that happens the opposite , but in the example in the link it's ok )
With my code below , I am taking as output:
ouMx =
4 7 0
7 5 9
0 9 6
so I think I am close!
I zeroed out the output matrix instead of having to insert zeros at the bottom or top of columns.
But I can't completeley handled the above/below the main diagonal.
I used if ( j > i ) swap rows , but it doesn't work , so I just use swap rows.
( I am assuming square matrix for this example ,but it should work for any matrix )
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
void Diag( int Rows , int Cols , float * inMx , float * ouMx );
void swapRows( int Rows , int Cols , float * Mx );
int main( int argc, const char* argv[] ){
int Rows = 3 , Cols = 3;
float *inMx = (float *) malloc ( Rows * Cols * sizeof (float) );
float *ouMx = (float *) malloc ( Rows * Cols * sizeof (float) );
// assume row major order
inMx[0] = 1.0;
inMx[1] = 0.0;
inMx[2] = 0.0;
inMx[3] = 4.0;
inMx[4] = 5.0;
inMx[5] = 6.0;
inMx[6] = 0.0;
inMx[7] = 7.0;
inMx[8] = 9.0;
// print input matrix ( row major )
printf("\n Input matrix \n\n");
for ( int i = 0; i < Rows; i++ )
for ( int j = 0; j < Cols; j++ ) {
printf("%f\t",inMx[ i * Cols + j ]);
if( j == Cols-1 )
printf("\n");
}
printf("\n");
// extract diagonals
Diag( Rows , Cols , inMx , ouMx );
// print Diagonal matrix
printf("\n Diagonal matrix \n\n");
for ( int i = 0; i < Rows; i++ )
for (int j = 0; j < Cols; j++ ) {
printf("%f\t",ouMx[ i * Cols + j ]);
if( j == Cols-1 )
printf("\n");
}
printf("\n");
free( inMx );
free( ouMx );
return 0;
}
void Diag( int Rows , int Cols , float * inMx , float * ouMx )
{
//zero out ouMx
memset( ouMx , 0 , Rows * Cols * sizeof(float) );
// scan from the last line to the first -1 for each column
for ( int j = 0; j < Cols; j++ )
{
for ( int i = ( Rows - 1 ); i > 0 ; i-- )
{
// neglect the zero elements
if ( inMx[ i * Cols + j ] != 0 )
{
ouMx[ i * Cols + j ] = inMx[ i * Cols + j ];
//if the element in the next colulmn is !=0
if ( inMx[ ( i + 1 ) * Cols + ( j + 1 ) ] != 0 )
{
ouMx[ ( i + 1 ) * Cols + j ] = inMx[ ( i + 1 ) * Cols + ( j + 1 ) ];
}
}
//if we are above the main diagonal
//swap elements of a row (in each column) in order to have the zeros at bottom/top
// if ( i > j ) doesn't work
swapRows( Rows , Cols , ouMx );
}
}
}
void swapRows( int Rows , int Cols , float * Mx )
{
float temp;
for ( int j = 0; j < Cols; j++ )
{
for ( int i = ( Rows - 1 ); i > 0 ; i-- )
{
temp = Mx[ ( i - 1 ) * Cols + j ];
Mx[ ( i - 1 ) * Cols + j ] = Mx[ i * Cols + j ];
Mx[ i * Cols + j ] = temp;
}
}
}
So I have an image that I want to overlay with a checkerboard pattern.
This is what I have come up with so far:
for ( uint_8 nRow = 0; nRow < image.width(); ++nRow)
for (uint_8 nCol = 0; nCol < image.height(); ++nCol)
if(((nRow/20 + nCol/20) % 2) == 0)
memset(&image.data[nCol + nRow], 0, 1);
Produces a white image unfortunately. I dont think this is very performant because memset is called for every single pixel in the image instead of multiple.
Why does this code not produce a chckerboard pattern? How would you improve it?
For better performance, don't treat the image as a 2-dimensional entity. Instead, look at it as a 1D array of continuous data, where all lines of the image are arranged one after the other.
With this approach, you can write the pattern in one go with a single loop, where in every iteration you memset() multiple adjacent pixels and increase the index by twice the amount of pixels you set:
int data_size = image.width() * image.height();
for (auto it = image.data; it < image.data + data_size; it += 20) {
memset(it, 0, 20);
if (((it - data) + 40) % (20 * 400) == 0) {
it += 40;
} else if (((it - data) + 20) % (20 * 400) != 0) {
it += 20;
}
}
(Replace auto with the type of image.data if you're not using C++11; I suspect it's unsigned char*.)
This is quite friendly for the CPU cache prefetch. It's also friendly for the compiler, which can potentially vectorize and/or perform loop unrolling.
If you have an image's dimensions which are multiple of the checker square size :
(I coded in C but it is fairly easy to transpose to C++)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define uint unsigned int
#define WIDTH 40
#define HEIGHT 40
#define BLOCK_SIZE 5
void create_checker_row(uint* row, uint size_block, uint nb_col, uint offset )
{
uint ic;
for (ic = size_block*offset ; ic < nb_col; ic+= 2*size_block )
{
memset( (row + ic) , 0, size_block*sizeof(uint) );
}
}
int main()
{
uint ir,ic;
// image creation
uint* pixels = (uint*) malloc(WIDTH*HEIGHT*sizeof(uint));
for (ir = 0; ir < WIDTH; ir++)
{
for ( ic = 0; ic < HEIGHT; ic++)
{
// arbitrary numbers
pixels[ir*WIDTH + ic] = (ir*WIDTH + ic) % 57 ;
printf("%d,", pixels[ir*WIDTH + ic] );
}
printf("\n");
}
for (ir = 0; ir < WIDTH; ir++)
{
create_checker_row( pixels + ir*WIDTH , // pointer at the beggining of n-th row
BLOCK_SIZE , // horizontal length for square
WIDTH , // image width
(ir/BLOCK_SIZE) % 2 // offset to create the checker pattern
);
}
// validation
printf("\n");
printf("Validation \n");
printf("\n");
for (ir = 0; ir < WIDTH; ir++)
{
for ( ic = 0; ic < HEIGHT; ic++)
{
printf("%d,", pixels[ir*WIDTH + ic] );
}
printf("\n");
}
return 0;
}
Seems pretty checkered for me : http://ideone.com/gp9so6
I use this and stb_image_write.h
#include <stdlib.h>
#include <stb_image_write.h>
int main(int argc, char *argv[])
{
const int w = 256, h = 256, ch = 4, segments = 8, box_sz = w / segments;
unsigned char rgba_fg[4] = {255, 255, 0, 255}; //yellow
unsigned char rgba_bg[4] = {255, 0, 0, 255}; //red
unsigned char* data = calloc(w * h * ch, sizeof(unsigned char));
int swap = 0;
int fill = 0; /* set to 1 to fill fg first*/
unsigned char* col = NULL;
for(int i = 0; i < w * h; i++)
{
if(i % (w * box_sz) == 0 && i != 0)
swap = !swap;
if(i % box_sz == 0 && i != 0)
fill = !fill;
if(fill)
{
if(swap)
col = rgba_bg;
else
col = rgba_fg;
}else
{
if(swap)
col = rgba_fg;
else
col = rgba_bg;
}
for(int j = 0; j < ch; j++)
{
data[i*ch + j] = col[j];
}
}
stbi_write_png("checker.png", w, h, ch, data, 0);
free(data);
return 0;
}
Its a bit slow with large images but gets the job done if you cache them