I'm calling the cvFindContours function inside a separate thread that I've created to handle all OpenCV work while another is kept for OpenGL stuff.
I noticed that my cvFindContours function always returns 0 when this code is executed inside a separate thread. It worked fine before, when executed in the main thread itself. I used breakpoints and Watches to evaluate value changes. everything else (variables) gets values except for contourCount (value: 0).
Any clue?
// header includes goes here
CvCapture* capture = NULL;
IplImage* frame = NULL;
IplImage* image;
IplImage* gray;
IplImage* grayContour;
CvMemStorage *storage;
CvSeq *firstcontour=NULL;
CvSeq *polycontour=NULL;
int contourCount = 0;
DWORD WINAPI startOCV(LPVOID vpParam){
capture = cvCaptureFromCAM(0); // NOTE 1
capture = cvCaptureFromCAM(0);
frame = cvQueryFrame(capture);
image = cvCreateImage(cvGetSize(frame), IPL_DEPTH_8U,3);
gray = cvCreateImage(cvGetSize(image), IPL_DEPTH_8U,1);
grayContour = cvCreateImage(cvGetSize(image), IPL_DEPTH_8U,1);
storage = cvCreateMemStorage (0);
firstcontour=NULL;
while(1){
frame = cvQueryFrame(capture);
cvCopy(frame,image);
cvCvtColor(image,gray,CV_BGR2GRAY);
cvSmooth(gray,gray,CV_GAUSSIAN,3);
cvThreshold (gray, gray, 0, 255, CV_THRESH_BINARY | CV_THRESH_OTSU);
cvNot(gray,gray);
cvCopy(gray,grayContour);
contourCount=cvFindContours (grayContour, storage, &firstcontour, sizeof (CvContour),
CV_RETR_CCOMP);
polycontour=cvApproxPoly(firstcontour,sizeof(CvContour),storagepoly,CV_POLY_APPROX_DP,3,1); // Error starts here (Pls refer to stack trace)
}
// goes on...
}
int main(int argc, char** argv){
DWORD qThreadID;
HANDLE ocvThread = CreateThread(0,0,startOCV, NULL,0, &qThreadID);
initGL(argc, argv); //some GL intitialization functions
glutMainLoop(); // draw some 3D objects
CloseHandle(ocvThread);
return 0;
}
NOTE1: these lines had to be duplicated due to the error mentioned at How to avoid "Video Source -> Capture source" selection in OpenCV 2.3.0 - Visual C++ 2008
Environment:
OpenCV 2.3.0
Visual C++ 2008
EDIT
Traces
opencv_core230d.dll!cv::error(const cv::Exception & exc={...}) Line 431 C++
opencv_imgproc230d.dll!cvPointSeqFromMat(int seq_kind=20480, const void * arr=0x00000000, CvContour * contour_header=0x01a6f514, CvSeqBlock * block=0x01a6f4f4) Line 47 + 0xbd bytes C++
opencv_imgproc230d.dll!cvApproxPoly(const void * array=0x00000000, int header_size=88, CvMemStorage * storage=0x017e7b40, int method=0, double parameter=3.0000000000000000, int parameter2=1) Line 703 + 0x28 bytes C++
Project.exe!startOCV(void * vpParam=0x00000000) Line 267 + 0x24 bytes C++
All this stuff boils down to the function CV_Assert( arr != 0 && contour_header != 0 && block != 0 ) in cvPointSeqFromMat and it fails since arr it requires is empty.
Your variable contourCount is not doing what you think it's doing. From the contours.cpp source file:
/*F///////////////////////////////////////////////////////////////////////////////////////
// Name: cvFindContours
// Purpose:
// Finds all the contours on the bi-level image.
// Context:
// Parameters:
// img - source image.
// Non-zero pixels are considered as 1-pixels
// and zero pixels as 0-pixels.
// step - full width of source image in bytes.
// size - width and height of the image in pixels
// storage - pointer to storage where will the output contours be placed.
// header_size - header size of resulting contours
// mode - mode of contour retrieval.
// method - method of approximation that is applied to contours
// first_contour - pointer to first contour pointer
// Returns:
// CV_OK or error code
// Notes:
//F*/
You are getting CV_OK == 0, which means it successfully ran. cvFindContours does not return the number of contours found to you. It merely lets you known if it failed or not. You should use the CvSeq* first_contour to figure out the number of contours detected.
Hope that helps!
Related
I am trying to convert an existing OpenCL kernel to an HLSL compute shader.
The OpenCL kernel samples each pixel in an RGBA texture and writes each color channel to a tighly packed array.
So basically, I need to write to a tightly packed uchar array in a pattern that goes somewhat like this:
r r r ... r g g g ... g b b b ... b a a a ... a
where each letter stands for a single byte (red / green / blue / alpha) that originates from a pixel channel.
going through the documentation for RWByteAddressBuffer Store method, it clearly states:
void Store(
in uint address,
in uint value
);
address [in]
Type: uint
The input address in bytes, which must be a multiple of 4.
In order to write the correct pattern to the buffer, I must be able to write a single byte to a non aligned address. In OpenCL / CUDA this is pretty trivial.
Is it technically possible to achieve that with HLSL?
Is this a known limitation? possible workarounds?
As far as I know it is not possible to write directly to a non aligned address in this scenario. You can, however, use a little trick to achieve what you want. Below you can see the code of the entire compute shader which does exactly what you want. The function StoreValueAtByte in particular is what you are looking for.
Texture2D<float4> Input;
RWByteAddressBuffer Output;
void StoreValueAtByte(in uint index_of_byte, in uint value) {
// Calculate the address of the 4-byte-slot in which index_of_byte resides
uint addr_align4 = floor(float(index_of_byte) / 4.0f) * 4;
// Calculate which byte within the 4-byte-slot it is
uint location = index_of_byte % 4;
// Shift bits to their proper location within its 4-byte-slot
value = value << ((3 - location) * 8);
// Write value to buffer
Output.InterlockedOr(addr_align4, value);
}
[numthreads(20, 20, 1)]
void CSMAIN(uint3 ID : SV_DispatchThreadID) {
// Get width and height of texture
uint tex_width, tex_height;
Input.GetDimensions(tex_width, tex_height);
// Make sure thread does not operate outside the texture
if(tex_width > ID.x && tex_height > ID.y) {
uint num_pixels = tex_width * tex_height;
// Calculate address of where to write color channel data of pixel
uint addr_red = 0 * num_pixels + ID.y * tex_width + ID.x;
uint addr_green = 1 * num_pixels + ID.y * tex_width + ID.x;
uint addr_blue = 2 * num_pixels + ID.y * tex_width + ID.x;
uint addr_alpha = 3 * num_pixels + ID.y * tex_width + ID.x;
// Get color of pixel and convert from [0,1] to [0,255]
float4 color = Input[ID.xy];
uint4 color_final = uint4(round(color.x * 255), round(color.y * 255), round(color.z * 255), round(color.w * 255));
// Store color channel values in output buffer
StoreValueAtByte(addr_red, color_final.x);
StoreValueAtByte(addr_green, color_final.y);
StoreValueAtByte(addr_blue, color_final.z);
StoreValueAtByte(addr_alpha, color_final.w);
}
}
I hope the code is self explanatory since it is hard to explain, but I'll try anyway.
The fist thing the function StoreValueAtByte does is to calculate the address of the 4-byte-slot enclosing the byte you want to write to. After that the position of the byte inside the 4-byte-slot is calculated (is it the fist, second, third or the fourth byte in the slot). Since the byte you want to write is already inside an 4-byte variable (namely value) and occupies the rightmost byte, you then just have to shift the byte to its proper position inside the 4-byte variable. After that you just have to write the variable value to the buffer at the 4-byte-aligned address. This is done using bitwise OR because multiple threads write to the same address interfering each other leading to write-after-write-hazards. This of course only works if you initialize the entire output buffer with zeros before issuing the dispatch-call.
On other Linux machines using the FBDEV drivers ( Raspberry Pi.. etc. ), I could mmap the /dev/fb0 device and directly create a BMP file that saved what was on the screen.
Now, I am trying to do the same thing with DRM on a TI Sitara AM57XX ( Beagleboard X-15 ). The code that used to work with FBDEV is shown below.
This mmap no longer seems to work the DRM. I'm using a very simple Qt5 Application with the Qt platform linuxfb plugin. It draws just fine into /dev/fb0 and shows on the screen properly, however I cannot read back from /dev/fb0 with a memory mapped pointer and have an image of the screen saved to file. It looks garbled like this:
Code:
#ifdef FRAMEBUFFER_CAPTURE
repaint();
QCoreApplication::processEvents();
// Setup framebuffer to desired format
struct fb_var_screeninfo var;
struct fb_fix_screeninfo finfo;
memset(&finfo, 0, sizeof(finfo));
memset(&var, 0, sizeof(var));
/* Get variable screen information. Variable screen information
* gives information like size of the image, bites per pixel,
* virtual size of the image etc. */
int fbFd = open("/dev/fb0", O_RDWR);
int fdRet = ioctl(fbFd, FBIOGET_VSCREENINFO, &var);
if (fdRet < 0) {
qDebug() << "Error opening /dev/fb0!";
close(fbFd);
return -1;
}
if (ioctl(fbFd, FBIOPUT_VSCREENINFO, &var)<0) {
qDebug() << "Error setting up framebuffer!";
close(fbFd);
return -1;
} else {
qDebug() << "Success setting up framebuffer!";
}
//Get fixed screen information
if (ioctl(fbFd, FBIOGET_FSCREENINFO, &finfo) < 0) {
qDebug() << "Error getting fixed screen information!";
close(fbFd);
return -1;
} else {
qDebug() << "Success getting fixed screen information!";
}
//int screensize = var.xres * var.yres * var.bits_per_pixel / 8;
//int screensize = var.yres_virtual * finfo.line_length;
//int screensize = finfo.smem_len;
int screensize = finfo.line_length * var.yres_virtual;
qDebug() << "Framebuffer size is: " << var.xres << var.yres << var.bits_per_pixel << screensize;
int linuxFbWidth = var.xres;
int linuxFbHeight = var.yres;
int location = (var.xoffset) * (var.bits_per_pixel/8) +
(var.yoffset) * finfo.line_length;
// Perform memory mapping of linux framebuffer
char* frameBufferMmapPixels = (char *)mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fbFd, 0);
assert(frameBufferMmapPixels != MAP_FAILED);
QImage toSave((uchar*)frameBufferMmapPixels,linuxFbWidth,linuxFbHeight,QImage::Format_ARGB32);
toSave.save("/usr/bin/test.bmp");
sync();
#endif
Here is the output of the code when it runs:
Success setting up framebuffer!
Success getting fixed screen information!
Framebuffer size is: 800 480 32 1966080
Here is the output of fbset showing the pixel format:
mode "800x480"
geometry 800 480 800 480 32
timings 0 0 0 0 0 0 0
accel true
rgba 8/16,8/8,8/0,8/24
endmode
root#am57xx-evm:~#
finfo.line_length gives the size of the actual physical scan line in bytes. It is not necessarily the same as screen width multiplied by pixel size, as scan lines may be padded.
However the QImage constructor you are using assumes no padding.
If xoffset is zero, it should be possible to construct a QImage directly from the framebuffer data using a constructor with the bytesPerLine argument. Otherwise there are two options:
allocate a separate buffer and copy only the visible portion of each scanline to it
create an image from the entire buffer (including the padding) and then crop it
If you're using DRM, then /dev/fb0 might point to an entirely different buffer (not the currently visible one) or have an different format.
fbdev is really just for old legacy that hasn't been ported DRM/KMS yet
and only has very limited modsetting capabilities.
BTW: which kernel are you using ? hopefully not that ancient and broken TI vendor kernel ...
I am trying to do some basic drawing with skia. Since I'm working on grayscale images I want to use the corresponding color type. The minimal Example I want to use is:
int main(int argc, char * const argv[])
{
int width = 1000;
int heigth = 1000;
float linewidth = 10.0f;
SkImageInfo info = SkImageInfo::Make(
width,
heigth,
SkColorType::kAlpha_8_SkColorType,
SkAlphaType::kPremul_SkAlphaType
);
SkBitmap img;
img.allocPixels(info);
SkCanvas canvas(img);
canvas.drawColor(SK_ColorBLACK);
SkPaint paint;
paint.setColor(SK_ColorWHITE);
paint.setAlpha(255);
paint.setAntiAlias(false);
paint.setStrokeWidth(linewidth);
paint.setStyle(SkPaint::kStroke_Style);
canvas.drawCircle(500.0f, 500.0f, 100.0f, paint);
bool success = SkImageEncoder::EncodeFile("B:\\img.png", img,
SkImageEncoder::kPNG_Type, 100);
return 0;
}
But the saved image does not contain the circle that was drawn. If I replace kAlpha_8_SkColorType with kN32_SkColorType I get the expected result. How can I draw the circle onto a 8 bit grayscale image? I'm working with Visual Studio 2013 on a 64bit Windows machine.
kN32_SkColorType type result
kAlpha_8_SkColorType result
You should use kGray_8_SkColorType than kAlpha_8_SkColorType.
The kAlpha_8_SkColorType used for bitmap mask.
I created a CUDA function for calculating the sum of an image using its histogram.
I'm trying to compile the kernel and the wrapper function for multiple compute capabilities.
Kernel:
__global__ void calc_hist(unsigned char* pSrc, int* hist, int width, int height, int pitch)
{
int xIndex = blockIdx.x * blockDim.x + threadIdx.x;
int yIndex = blockIdx.y * blockDim.y + threadIdx.y;
#if __CUDA_ARCH__ > 110 //Shared Memory For Devices Above Compute 1.1
__shared__ int shared_hist[256];
#endif
int global_tid = yIndex * pitch + xIndex;
int block_tid = threadIdx.y * blockDim.x + threadIdx.x;
if(xIndex>=width || yIndex>=height) return;
#if __CUDA_ARCH__ == 110 //Calculate Histogram In Global Memory For Compute 1.1
atomicAdd(&hist[pSrc[global_tid]],1); /*< Atomic Add In Global Memory */
#elif __CUDA_ARCH__ > 110 //Calculate Histogram In Shared Memory For Compute Above 1.1
shared_hist[block_tid] = 0; /*< Clear Shared Memory */
__syncthreads();
atomicAdd(&shared_hist[pSrc[global_tid]],1); /*< Atomic Add In Shared Memory */
__syncthreads();
if(shared_hist[block_tid] > 0) /* Only Write Non Zero Bins Into Global Memory */
atomicAdd(&(hist[block_tid]),shared_hist[block_tid]);
#else
return; //Do Nothing For Devices Of Compute Capabilty 1.0
#endif
}
Wrapper Function:
int sum_8u_c1(unsigned char* pSrc, double* sum, int width, int height, int pitch, cudaStream_t stream = NULL)
{
#if __CUDA_ARCH__ == 100
printf("Compute Capability Not Supported\n");
return 0;
#else
int *hHist,*dHist;
cudaMalloc(&dHist,256*sizeof(int));
cudaHostAlloc(&hHist,256 * sizeof(int),cudaHostAllocDefault);
cudaMemsetAsync(dHist,0,256 * sizeof(int),stream);
dim3 Block(16,16);
dim3 Grid;
Grid.x = (width + Block.x - 1)/Block.x;
Grid.y = (height + Block.y - 1)/Block.y;
calc_hist<<<Grid,Block,0,stream>>>(pSrc,dHist,width,height,pitch);
cudaMemcpyAsync(hHist,dHist,256 * sizeof(int),cudaMemcpyDeviceToHost,stream);
cudaStreamSynchronize(stream);
(*sum) = 0.0;
for(int i=1; i<256; i++)
(*sum) += (hHist[i] * i);
printf("sum = %f\n",(*sum));
cudaFree(dHist);
cudaFreeHost(hHist);
return 1;
#endif
}
Question 1:
When compiling for sm_10, the wrapper and the kernel shouldn't execute. But that is not what happens. The whole wrapper function executes. The output shows sum = 0.0.
I expected the output to be Compute Capability Not Supported as I have added the printf statement in the start of the wrapper function.
How can I prevent the wrapper function from executing on sm_10? I don't want to add any run-time checks like if statements etc. Can it be achieved through template meta programming?
Question 2:
When compiling for greater than sm_10, the program executes correctly only if I add cudaStreamSynchronize after the kernel call. But if I do not synchronize, the output is sum = 0.0. Why is it happening? I want the function to be asynchronous w.r.t the host as much as possible. Is it possible to shift the only loop inside the kernel?
I am using GTX460M, CUDA 5.0, Visual Studio 2008 on Windows 8.
Ad. Question 1
As already Robert explained in the comments - __CUDA_ARCH__ is defined only when compiling device code. To clarify: when you invoke nvcc, the code is parsed and compiled twice - once for CPU and once for GPU. The existence of __CUDA_ARCH__ can be used to check which of those two passes occurs, and then for the device code - as you do in the kernel - it can be checked which GPU are you targetting.
However, for the host side it is not all lost. While you don't have __CUDA_ARCH__, you can call API function cudaGetDeviceProperties which returns lots of information about your GPU. In particular, you can be interested in fields major and minor which indicate the Compute Capability. Note - this is done at run-time, not a preprocessing stage, so the same CPU code will work on all GPUs.
Ad. Question 2
Kernel calls and cudaMemoryAsync are asynchronous. It means that if you don't call cudaStreamSynchronize (or alike) the followup CPU code will continue running even if your GPU hasn't finished your work. This means, that the data you copy from dHist to hHist might not be there yet when you begin operating on hHist in the loop. If you want to work on the output from a kernel you have to wait till the kernel finishes.
Note that cudaMemcpy (without Async) has an implicit synchronization inside.
Error 3 error C2059: syntax error : ')' c:\program files\microsoft visual studio 10.0\vc\include\string 758 1 ECE572_001_Project1_swirl
Error 6 error C2059: syntax error : ')' c:\program files\microsoft visual studio 10.0\vc\include\string 767 1 ECE572_001_Project1_swirl
Error 1 error C2143: syntax error : missing ')' before 'string' c:\program files\microsoft visual studio 10.0\vc\include\string 758 1 ECE572_001_Project1_swirl
Error 4 error C2143: syntax error : missing ')' before 'string' c:\program files\microsoft visual studio 10.0\vc\include\string 767 1 ECE572_001_Project1_swirl
Error 2 error C2665: 'swprintf' : none of the 2 overloads could convert all the argument types c:\program files\microsoft visual studio 10.0\vc\include\string 758 1 ECE572_001_Project1_swirl
Error 5 error C2665: 'swprintf' : none of the 2 overloads could convert all the argument types c:\program files\microsoft visual studio 10.0\vc\include\string 767 1 ECE572_001_Project1_swirl
I don't understand this error, because it says the error is in the file string, which is a locked file provided by VS2010. Second, I'm not even using string, and third, how could including complex have anything to do with the library string?
Even though including complex causes the error in my project file, I started a whole new file to test including it, and the error didn't happen there.
#include "Image.h"
#include <iostream>
#include <complex>
using namespace std;
#define Usage "makeSwirl inImg outImg coeff\n"
/*
* arg1 is the image to transform.
* arg2 is the swirl coefficient
* Returns image with enhanced edges.
*/
Image swirl(const Image&, const float&);
/*
* arg1 is the image within which the pixel to be transformed is located.
* arg2&3&4 are the row, colum, and channel of the pixel to transform.
* arg5 is the swirl coefficient
* arg6&7 are the rows and cols of arg1.
* returns transformed pixel.
*/
float onePixelSwirl(const Image&, const int&, const int&, const int&, const double&, const int&, const int&);
int main(int argc, char **argv)
{
// Check for proper number of arguments.
if(argc != 4)
{
cout << Usage;
exit(3);
}
// Read in image specified by user.
const Image IN_IMG = readImage(argv[1]);
// Create output image with oil effect.
Image outImg = swirl(IN_IMG, atof(argv[3]));
// Output the image
writeImage(outImg, argv[2]);
// Success!
return(0);
}
Image swirl(const Image& IN_IMG, const float& COEFF)
{
Image outImg;
// Allocate memory
const int ROWS = IN_IMG.getRow();
const int COLS = IN_IMG.getCol();
const int CHANNELS = IN_IMG.getChannel();
outImg.createImage(ROWS, COLS, IN_IMG.getType());
// Perform edge effect
for (int k = 0; k < CHANNELS; ++k)
for (int i = 0; i < ROWS; ++i)
for (int j = 0; j < COLS; ++j)
outImg(i,j,k) = onePixelSwirl(IN_IMG, i, j, k, COEFF, ROWS, COLS);
return outImg;
}
float onePixelSwirl(const Image& IN_IMG, const int& ROW, const int& COL,
const int& CHANNEL, const double& COEFF, const int& ROWS, const int& COLS)
{
// define shift of origin
//const double X_SHIFT = ROWS/2.0;
//const double Y_SHIFT = COLS/2.0;
//const complex<double> NEW_SHIFTED(ROW - X_SHIFT, COL - Y_SHIFT);
//const double r = abs(NEW_SHIFTED);
//const complex<double> OLD_SHIFTED = polar(r, arg(NEW_SHIFTED) + r/COEFF);
//const int OLD_ROW = OLD_SHIFTED.real() <= ROWS ? OLD_SHIFTED.real() : ROWS;
//const int OLD_COL = OLD_SHIFTED.imag() <= COLS ? OLD_SHIFTED.imag() : COLS;
//return IN_IMG(OLD_ROW, OLD_COL, CHANNEL);
return 0;
}
I put the include statement above including image.h, and the compilation bugs vanished. Here is image.h if someone could figure out the problem:
/********************************************************************
* Image.h - header file of the Image library which defines
* a new class "Image" and the associated member functions
*
* Author: Hairong Qi, hqi#utk.edu, ECE, University of Tennessee
*
* Created: 02/05/02
*
* Note:
* This is a simple C++ library for image processing.
* The purpose is not high performance, but to show how
* the algorithm works through programming.
* This library can only read in PGM/PPM format images.
*
* Modification:
* 07/31/09 - moving header files for colorProcessing, imageIO, and
* matrixProcessing to this file
* 01/22/06 - reorganize the Image library such that the Image class
* only contains member functions related to the most
* fundamental image operation
* 11/12/05 - add wavelet transform function
* 09/26/05 - add Fourier transform related functions
* 09/07/05 - add overloading function for "/"
* 09/07/05 - modify createImage() function
* 09/07/05 - fix problems with copy constructor
* 08/07/05 - regrouping functions
********************************************************************/
#ifndef IMAGE_H
#define IMAGE_H
#include <iostream>
#include <cmath>
using namespace std;
#define PGMRAW 1 // magic number is 'P5'
#define PPMRAW 2 // magic number is 'P6'
#define PGMASCII 3 // magic number is 'P2'
#define PPMASCII 4 // magic number is 'P3'
#define GRAY 10 // gray-level image
#define BINARY 11 // binary image
#define NBIT 8
#define L ( pow(2.0,NBIT)-1 ) // the largest intensity represented by NBIT
class Image {
friend ostream & operator<<(ostream &, Image &);
friend Image operator/(Image &, double); // image divided by a scalar
friend Image operator*(Image &, double); // image multiplied by a scalar
friend Image operator+(Image &, double); // image add a scalar
friend Image operator-(Image &, double); // image subtract a scalar
public:
// constructors and destructor
Image(); // default constructor
Image(int, // constructor with row
int, // column
int t=PGMRAW); // type (use PGMRAW, PPMRAW,
// PGMASCII, PPMASCII)
Image(const Image &); // copy constructor
~Image(); // destructor
// create an image
void createImage(); // create an image, parameters all set
void createImage(int, // create an image with row
int c=1, // column (default 1, a column vector)
int t=PGMRAW); // and type, default is PGMRAW
void initImage(float init=0.0); // initiate the pixel value of an img
// the default is 0.0
// get and set functions
int getRow() const; // get row # / the height of the img
int getCol() const; // get col # / the width of the image
int getChannel() const; // get channel number of the image
int getType() const; // get the image type
float getMaximum() const; // get the maximum pixel value
void getMaximum(float &, // return the maximum pixel value
int &, int &); // and its indices
float getMinimum() const; // get the mininum pixel value
void getMinimum(float &, // return the minimum pixel value
int &, int &); // and its indices
Image getRed() const; // get the red channel
Image getGreen() const; // get the green channel
Image getBlue() const; // get the blue channel
Image getImage(int) const; // get the kth channel image,
// k starts at 0
void setRow(int); // set row number
void setCol(int); // set column number
void setChannel(int); // set the number of channel
void setType(int t=PGMRAW); // set the image type
void setRed(Image &); // set the red channel
void setGreen(Image &); // set the green channel
void setBlue(Image &); // set the blue channel
void setImage(Image &, int); // set the kth channel image,
// k starts at 0
// operator overloading functions
float & operator()(int, // operator overloading (i,j,k)
int c = 0, // when c=k=0, a column vector
int k = 0) const;
const Image operator=(const Image &); // = operator overloading
Image operator+(const Image &) const; // overloading + operator
Image operator-(const Image &) const; // overloading - operator
Image operator*(const Image &) const; // overloading pixelwise *
Image operator/(const Image &) const; // overloading pixelwise division
Image operator->*(const Image &) const; // overloading ->* operator
// (matrix multiplication)
bool IsEmpty() const { return (image==NULL); }
private:
int row; // number of rows / height
int col; // number of columns / width
int channel; // nr of channels (1 for gray, 3 for color)
int type; // image type (PGM, PPM, etc.)
int maximum; // the maximum pixel value
float *image; // image buffer
};
////////////////////////////////////
// image I/O
Image readImage(char *); // read image
void writeImage(Image &, // write an image
char *,
int flag=0); // flag for rescale, rescale when == 1
Image rescale(Image &, // rescale an image
float a=0.0, // lower bound
float b=L); // upper bound
////////////////////////////////////
// color processing routines
Image RGB2HSI(Image &); // convert from RGB to HSI model
Image HSI2RGB(Image &); // convert from HSI to RGB model
////////////////////////////////////
// matrix manipulation
Image transpose(Image &); // image transpose
Image inverse(Image &); // image inverse
Image pinv(Image &); // image pseudo-inverse
Image subImage(Image &, // crop an image
int, // starting row index
int, // starting column index
int, // ending row index
int); // ending column index
#endif
There's a number of things that are suspicious but the main one is the definition of L. If I recall, L is used to indicate a Unicode string literal as in L"Some Unicode text". It seems likely that <complex> uses this. By including Image.h before <complex>, you've redefined it. This would also explain the broken calls to swprintf().
Since you don't use L in Image.h is there any reason to declare it there? If L is part of the interface and actually needs to be in the header file, consider renaming it to something less likely to provoke a name conflict.
Other things that look suspicious but aren't necessarily the problem here: You've included <cmath> in Image.h for no apparent reason. Generally, you should only include the files you actually need. A bigger issue is the using namespace std in the header. This is almost always a bad idea since it pulls every name in the std namespace into the local scope of every file that includes this header file. It greatly increases the chance of name collisions that could be tricky to sort out (as you can see)