iam writing a program to represent a blur efect on a bitmap.
Blur efect code:
for (xx = 0; xx < bitmapInfoHeader.biWidth; xx++)
{
for (yy = 0; yy <bitmapInfoHeader.biHeight; yy++)
{
avgB = avgG = avgR = 0;
Counter = 0;
for (x = xx; x < bitmapInfoHeader.biWidth && x < xx + blurSize; x++)
{
for (y = yy; y < bitmapInfoHeader.biHeight && y < yy + blurSize; y++)
{
avgB += bitmapImage[x *3 + y*bitmapInfoHeader.biWidth * 3 + 0]; //bitmapimage[x][y];
avgG += bitmapImage[x *3 + y*bitmapInfoHeader.biWidth * 3 + 1];
avgR += bitmapImage[x *3 + y*bitmapInfoHeader.biWidth * 3 + 2];
Counter++;
}
}
avgB = avgB / Counter;
avgG = avgG / Counter;
avgR = avgR / Counter;
bitmapImage[xx * 3 + yy*bitmapInfoHeader.biWidth * 3 + 0] = avgB;
bitmapImage[xx * 3 + yy*bitmapInfoHeader.biWidth * 3 + 1] = avgG;
bitmapImage[xx * 3 + yy*bitmapInfoHeader.biWidth * 3 + 2] = avgR;
}
}
And my output function which take the blured Array "bitmapImage" to a new file:
out = fopen(file,"wb");
fwrite(&bitmapInfoHeader, sizeof(char), sizeof(BITMAPINFOHEADER), out);
fwrite(&bitmapFileHeader, sizeof(char), sizeof(BITMAPFILEHEADER), out);
fseek(out, sizeof(char)*bitmapFileHeader.bfOffBits, SEEK_SET);
fwrite(bitmapImage, sizeof(char), bitmapInfoHeader.biSizeImage, out);
The reading function:
BITMAPINFOHEADER bitmapInfoHeader;
FILE *filePtr,*out;
BITMAPFILEHEADER bitmapFileHeader;
unsigned char *bitmapImage = nullptr;
filePtr = fopen(filename, "rb");
if (filePtr == NULL)
return NULL;
fread(&bitmapFileHeader, sizeof(BITMAPFILEHEADER), 1, filePtr);
fread(&bitmapInfoHeader, sizeof(BITMAPINFOHEADER), 1, filePtr);
fseek(filePtr, bitmapFileHeader.bfOffBits, SEEK_SET);
//bitmapImage = (unsigned char*)malloc(bitmapInfoHeader->biSizeImage);
bitmapImage = new unsigned char[bitmapInfoHeader.biSizeImage];
fread(bitmapImage, sizeof(char), bitmapInfoHeader.biSizeImage,filePtr);
*size = bitmapInfoHeader.biSizeImage;
When i compile the program a new bmp file is created but the image viewer cant show it and thorw an error.
So what am doing wrong here? is the blur algorytm good?
Related
what is wrong with that following code ?
Compiles and executes fine, but doesnt produce any sound... BTW could anyone point me to how produce stereo left and right sound ?
void audio()
{ WAVEHDR _audioHeader;
HWAVEOUT _audioOut = 0;
WAVEFORMATEX _audioStyle;
_audioStyle.wFormatTag = WAVE_FORMAT_PCM;
_audioStyle.nChannels = 1;
_audioStyle.nSamplesPerSec = 44100;
_audioStyle.nAvgBytesPerSec = 44100 * 2;
_audioStyle.nBlockAlign = 2;
_audioStyle.wBitsPerSample = 16;
_audioStyle.cbSize = 0;
_audioHeader.lpData = new char[44100 * 2];
_audioHeader.dwBufferLength = 44100 * 2;
_audioHeader.dwBytesRecorded = 0;
_audioHeader.dwUser = 0;
_audioHeader.dwFlags = WHDR_BEGINLOOP | WHDR_ENDLOOP;
_audioHeader.dwLoops = 0xFFFF;
_audioHeader.lpNext = NULL;
_audioHeader.reserved = 0;
for(unsigned _x = 0; _x < _audioHeader.dwBufferLength / 2; _x += 2)
{ const
double _byte = 128 + 127 * ::cos(double(_x) * 2.0 * M_PI * double(2400) / double(_audioStyle.nSamplesPerSec));
_audioHeader.lpData[_x + 0] = (char)(_byte);
_audioHeader.lpData[_x + 1] = (char)(_byte);
}
::waveOutOpen(&_audioOut, WAVE_MAPPER, &_audioStyle, NULL, NULL, CALLBACK_NULL);
::waveOutPrepareHeader(&_audioOut, &_audioHeader, sizeof(WAVEHDR));
::waveOutWrite(&_audioOut, &_audioHeader, sizeof(WAVEHDR));
::Beep(1200, 500); ::Sleep(1000); ::Beep(2400, 500);
if(_audioOut != 0)
{ ::waveOutReset(&_audioOut);
::waveOutClose(&_audioOut);
::delete [] _audioHeader.lpData;
}
}
after some research, I found that nBlockAlign has to be computed, wBitsPerSample reduced to 8, and mainly, as waveoutopen requires a pointer to HWAVEOUT, other functions only require the handle….
code became :
{ WAVEHDR _audioHeader;
HWAVEOUT _audioOut = 0;
WAVEFORMATEX _audioStyle;
_audioStyle.wFormatTag = WAVE_FORMAT_PCM;
_audioStyle.nChannels = 2;
_audioStyle.nSamplesPerSec = 44100;
_audioStyle.nAvgBytesPerSec = _audioStyle.nSamplesPerSec * _audioStyle.nChannels;
_audioStyle.wBitsPerSample = 8;
_audioStyle.nBlockAlign = (_audioStyle.wBitsPerSample / 8) * _audioStyle.nChannels;
_audioStyle.cbSize = 0;
_audioHeader.dwBufferLength = _audioStyle.nAvgBytesPerSec;
_audioHeader.lpData = new char[_audioHeader.dwBufferLength];
_audioHeader.dwBytesRecorded = 0;
_audioHeader.dwUser = 0;
_audioHeader.dwFlags = WHDR_BEGINLOOP | WHDR_ENDLOOP;
_audioHeader.dwLoops = 0xFFFF;
_audioHeader.lpNext = NULL;
_audioHeader.reserved = 0;
for(unsigned _x = 0; _x < _audioHeader.dwBufferLength; _x += 2)
{ const
double _byte = ::cos(double(_x) * 2.0 * M_PI * double(2400) / double(_audioStyle.nSamplesPerSec));
if(_x > (_audioHeader.dwBufferLength / 2))
{ _audioHeader.lpData[_x + 0] = (char)(128 + 127 * 0);
_audioHeader.lpData[_x + 1] = (char)(128 + 127 * _byte);
}
else
{ _audioHeader.lpData[_x + 0] = (char)(128 + 127 * _byte);
_audioHeader.lpData[_x + 1] = (char)(128 + 127 * 0);
}
}
if(::waveOutOpen(&_audioOut, WAVE_MAPPER, &_audioStyle, NULL, NULL, CALLBACK_NULL) == 0)
if(::waveOutPrepareHeader(_audioOut, &_audioHeader, sizeof(WAVEHDR)) == 0)
::waveOutWrite(_audioOut, &_audioHeader, sizeof(WAVEHDR));
::Sleep(1000);
if(_audioOut != 0)
{ ::waveOutReset(_audioOut);
::waveOutClose(_audioOut);
::delete [] _audioHeader.lpData;
}
}
I am trying to apply the sobel filter algorithm to a given picture (grayscale in this case) given my approach to accessing the pixels of the picture. Since I am accessing them in a way that doesn't use libraries, I am having trouble figuring out how to apply the algorithm given this approach. This first part of the code is just accessing pixel data:
Part 1:
CKingimageDoc* pDoc = GetDocument(); // get picture
int iBitPerPixel = pDoc->_bmp->bitsperpixel; // used to see if grayscale(8 bits) or RGB (24 bits)
int iWidth = pDoc->_bmp->width;
int iHeight = pDoc->_bmp->height;
BYTE *pImg = pDoc->_bmp->point; // pointer used to point at pixels in the image
const int area = iWidth * iHeight;
int Wp = iWidth;
int intensity;
if (iBitPerPixel == 8) ////Grayscale 8 bits image
{
int r = iWidth % 4; // pixels leftover from width (remainder has to be factor of 8 or 24)
int p = (4-r) % 4; // has to be a factor of number of bits in pixel, num leftover to take care of
Wp = iWidth + p;
Part 2 (The actual application of the sobel filter algorithm):
float kernelx[3][3] = { { -1, 0, 1 },
{ -2, 0, 2 },
{ -1, 0, 1 } };
float kernely[3][3] = { { -1, -2, -1 },
{ 0, 0, 0 },
{ 1, 2, 1 } };
double magX = 0.0; // this is your magnitude
for (int a = 0; a < 3; a++) {
for (int b = 0; b < 3; b++) {
magX += pImg[i*Wp + j] * kernelx[a][b]; // where i get confused
}
}
}
Any and all help is greatly appreciated.
You have to use appropriate pixel from neighborhood of center pixel to multiply with kernel entry:
//row, col - coordinates of central pixel for calculation
for (int row = 1; row < height - 1; row++) {
for (int col = 1; col < width - 1; col++) {
double magX = 0.0; // this is your magnitude
for (int a = 0; a < 3; a++) {
for (int b = 0; b < 3; b++) {
magX += pImg[(row - 1 + a) * Wp + col - 1 + b] * kernelx[a][b];
}
}
resultImg[row * Wp + col] = magX;
}
}
I omitted border pixels
CKingimageDoc* pDoc = GetDocument(); // get picture
int iBitPerPixel = pDoc->_bmp->bitsperpixel; // used to see if grayscale(8b) or RGB(24b)
int iWidth = pDoc->_bmp->width;
int iHeight = pDoc->_bmp->height;
BYTE *pImg = pDoc->_bmp->point; // pointer used to point at pixels in the image
const int area = iWidth * iHeight;
BYTE *pImg2 = new BYTE[area];
if (iBitPerPixel == 8) // Grayscale 8bit image
{
int pixel_x;
int pixel_y;
float sobel_x[3][3] =
{ { -1, 0, 1 },
{ -2, 0, 2 },
{ -1, 0, 1 } };
float sobel_y[3][3] =
{ { -1, -2, -1 },
{ 0, 0, 0 },
{ 1, 2, 1 } };
for (int x=1; x < iWidth-1; x++)
{
for (int y=1; y < iHeight-1; y++)
{
pixel_x = (sobel_x[0][0] * pImg[iWidth * (y-1) + (x-1)])
+ (sobel_x[0][1] * pImg[iWidth * (y-1) + x ])
+ (sobel_x[0][2] * pImg[iWidth * (y-1) + (x+1)])
+ (sobel_x[1][0] * pImg[iWidth * y + (x-1)])
+ (sobel_x[1][1] * pImg[iWidth * y + x ])
+ (sobel_x[1][2] * pImg[iWidth * y + (x+1)])
+ (sobel_x[2][0] * pImg[iWidth * (y+1) + (x-1)])
+ (sobel_x[2][1] * pImg[iWidth * (y+1) + x ])
+ (sobel_x[2][2] * pImg[iWidth * (y+1) + (x+1)]);
pixel_y = (sobel_y[0][0] * pImg[iWidth * (y-1) + (x-1)])
+ (sobel_y[0][1] * pImg[iWidth * (y-1) + x ])
+ (sobel_y[0][2] * pImg[iWidth * (y-1) + (x+1)])
+ (sobel_y[1][0] * pImg[iWidth * y + (x-1)])
+ (sobel_y[1][1] * pImg[iWidth * y + x ])
+ (sobel_y[1][2] * pImg[iWidth * y + (x+1)])
+ (sobel_y[2][0] * pImg[iWidth * (y+1) + (x-1)])
+ (sobel_y[2][1] * pImg[iWidth * (y+1) + x ])
+ (sobel_y[2][2] * pImg[iWidth * (y+1) + (x+1)]);
int val = (int)sqrt((pixel_x * pixel_x) + (pixel_y * pixel_y));
if(val < 0) val = 0;
if(val > 255) val = 255;
pImg2[iHeight * y + x] = val;
}
}
}
EDIT : The question was not clear sorry, I updated and added details.
I have a buffer with image data (YUV format) that I convert to an RGB format. The problem is, I would like to flip the image vertically (Invert the Y-position).
What I'm able to do for the moment is convert my YUV data to RGB data in a buffer, then flip this buffer vertically.
Here is the working code for this :
unsigned char* DeckLinkCaptureDelegate::convertYUVtoRGB(void* frameBytes)
{
unsigned char *mycopy = new unsigned char[height*width*3];
unsigned char *flippedCopy = new unsigned char[height*width*3];
unsigned char* pData = (unsigned char *) frameBytes;
//Conversion from YUV to RGB
for(int i = 0, j=0; i < width * height * 3; i+=6, j+=4)
{
unsigned char v = pData[j];
unsigned char y = pData[j+1];
unsigned char u = pData[j+2];
mycopy[i+2] = 1.0*y + 8 + 1.402*(v-128); // r
mycopy[i+1] = 1.0*y - 0.34413*(u-128) - 0.71414*(v-128); // g
mycopy[i] = 1.0*y + 1.772*(u-128) + 0; // b
y = pData[j+3];
mycopy[i+5] = 1.0*y + 8 + 1.402*(v-128); // r
mycopy[i+4] = 1.0*y - 0.34413*(u-128) - 0.71414*(v-128); // g
mycopy[i+3] = 1.0*y + 1.772*(u-128) + 0;
}
//Vertical flip
for (int i = 0; i < width; ++i) {
for (int j = 0; j < height; ++j) {
for (int k = 0; k < 3; ++k) {
flippedCopy[(i + j * width) * 3 + k] = mycopy[(i + (height - 1 - j) * width) * 3 + k];
}
}
}
return flippedCopy;
}
What I would like to do to gain performance is flip the buffer DURING the conversion from YUV to RGB. I had no idea how to do it and Yusuf answer helped me, so here is what I have for the moment :
unsigned char* DeckLinkCaptureDelegate::convertYUVtoRGB(void* frameBytes)
{
unsigned char *mycopy = new unsigned char[height*width*3];
unsigned char* pData = (unsigned char *) frameBytes;
int k = height - 1;
for(int i = 0, j=0; i < width * height * 3; i+=6, j+=4)
{
unsigned char v = pData[j];
unsigned char y = pData[j+1];
unsigned char u = pData[j+2];
mycopy[(width*k*3) + i+2] = 1.0*y + 8 + 1.402*(v-128); // r
mycopy[(width*k*3) + i+1] = 1.0*y - 0.34413*(u-128) - 0.71414*(v-128); // g
mycopy[(width*k*3) + i] = 1.0*y + 1.772*(u-128) + 0; // b
y = pData[j+3];
mycopy[(width*k*3) + i+5] = 1.0*y + 8 + 1.402*(v-128); // r
mycopy[(width*k*3) + i+4] = 1.0*y - 0.34413*(u-128) - 0.71414*(v-128); // g
mycopy[(width*k*3) + i+3] = 1.0*y + 1.772*(u-128) + 0;
if (<i multiple of (width*3)-1>){
k = k - 2;
}
}
return mycopy;
}
If I'm correct, this should work, assuming the if condition is right. But I don't know how to express this if condition, since i is incremented by 6 each time, so I might "skip" the right moment to decrement k
I hope I'm clear enough. Thanks
I assume that width is even, otherwise "reduce in new line"-if will be complicated, then you must use 2 loops. I didn't tested, but should look like this;
unsigned char* DeckLinkCaptureDelegate::convertYUVtoRGB(void* frameBytes)
{
unsigned char *mycopy = new unsigned char[height*width*3];
unsigned char* pData = (unsigned char *) frameBytes;
unsigned int k = height - 1;
for(int i = 0, j=0; i < width * height * 3; i+=6, j+=4)
{
unsigned char v = pData[j];
unsigned char y = pData[j+1];
unsigned char u = pData[j+2];
mycopy[(width*k*3) + i+2] = 1.0*y + 8 + 1.402*(v-128); // r
mycopy[(width*k*3) + i+1] = 1.0*y - 0.34413*(u-128) - 0.71414*(v-128); // g
mycopy[(width*k*3) + i] = 1.0*y + 1.772*(u-128) + 0; // b
y = pData[j+3];
mycopy[(width*k*3) + i+5] = 1.0*y + 8 + 1.402*(v-128); // r
mycopy[(width*k*3) + i+4] = 1.0*y - 0.34413*(u-128) - 0.71414*(v-128); // g
mycopy[(width*k*3) + i+3] = 1.0*y + 1.772*(u-128) + 0;
if (mod(i, width*3) == 0) //reduce in new line (i am not sure how to reduce it, you should think about here)
k = k - 2;
}
return mycopy;
}
And tag your question as imageprocessing etc not only as c++
void LBP(Mat src, IplImage* dst)
{
int tmp[8] = { 0 };
CvScalar s;
Mat temp = Mat(src.size(), IPL_DEPTH_8U, 1);
uchar *data = (uchar*)src.data;
int step = src.step;
//cout << "step" << step << endl;
for (int i = 1; i<src.size().height - 1; i++)
for (int j = 1; j<src.size().width - 1; j++)
{
int sum = 0;
if (data[(i - 1)*step + j - 1]>data[i*step + j])
tmp[0] = 1;
else
tmp[0] = 0;
if (data[i*step + (j - 1)]>data[i*step + j])
tmp[1] = 1;
else
tmp[1] = 0;
if (data[(i + 1)*step + (j - 1)]>data[i*step + j])
tmp[2] = 1;
else
tmp[2] = 0;
if (data[(i + 1)*step + j]>data[i*step + j])
tmp[3] = 1;
else
tmp[3] = 0;
if (data[(i + 1)*step + (j + 1)]>data[i*step + j])
tmp[4] = 1;
else
tmp[4] = 0;
if (data[i*step + (j + 1)]>data[i*step + j])
tmp[5] = 1;
else
tmp[5] = 0;
if (data[(i - 1)*step + (j + 1)]>data[i*step + j])
tmp[6] = 1;
else
tmp[6] = 0;
if (data[(i - 1)*step + j]>data[i*step + j])
tmp[7] = 1;
else
tmp[7] = 0;
s.val[0] = (tmp[0] * 1 + tmp[1] * 2 + tmp[2] * 4 + tmp[3] * 8 + tmp[4] * 16 + tmp[5] * 32 + tmp[6] * 64 + tmp[7] * 128);
cvSet2D(dst, i, j, s);
}
}
Above is my original code for local binary pattern, src is an input matrix and dst is the output. Now i want to change the IPLimage in void LBP(Mat src, IplImage* dst) to void LBP(Mat src, mat dst), i tried many ways but I always met problems like assertion failed or something else, i thinks it might be the problem of cvSet2D(dst, i, j, s);
this is the definition for the input src:
Mat Gray_face = Mat(image.size(), image.depth(), 1);
this is my definition for output dst:
IplImage* lbp_face = cvCreateImage(Gray_face.size(), IPL_DEPTH_8U, 1);
And i want to change it to mat and make it work for my program.
this is how i call the LBP function:
LBP(Gray_face, lbp_face);
I am quite new to this, can anyone help me? thank you very much!
Indeed cvSet2D is the old interface. To set a point to a cv::Mat dst you can use at(). Fisrt, you first (re)allocate it as:
dst.create(src.size(),CV_8U);
Then to set a value point in your case:
dst.at<char>(i,j) = (tmp[0] * 1 + tmp[1] * 2 + tmp[2] * 4 + tmp[3] * 8 + tmp[4] * 16 + tmp[5] * 32 + tmp[6] * 64 + tmp[7] * 128);
Last but not least, if you want the result returned, you function definition should be:
void LBP(Mat src, Mat & dst);
with a reference (&) to the destination.
I am using Qt,OpenCV and libJpeg to compress a YUV422 image, but the output is not correct.
if I convert the yuv to rgb and then compress, I get a correct output, but what I understand that Jpeg is using YUV internally , that's why I want to remove redundancy.
Here is my code:
bool ipl2jpeg(IplImage *frame, unsigned char **outbuffer, long unsigned int *outlen) {
unsigned char *outdata = (uchar *) frame->imageData;
struct jpeg_compress_struct cinfo ;
struct jpeg_error_mgr jerr;
JSAMPROW row_ptr[1];
int row_stride;
*outbuffer = NULL;
*outlen = 0;
cinfo.err = jpeg_std_error(&jerr);
jpeg_create_compress(&cinfo);
jpeg_mem_dest(&cinfo, outbuffer, outlen);
cinfo.image_width = frame->width;
cinfo.image_height = frame->height;
cinfo.input_components = frame->nChannels;
cinfo.in_color_space = JCS_YCbCr;
jpeg_set_defaults(&cinfo);
jpeg_set_quality (&cinfo,100 , true);
jpeg_start_compress(&cinfo, TRUE);
row_stride = frame->width *2;// frame->nChannels;
while (cinfo.next_scanline < cinfo.image_height) {
/* jpeg_write_scanlines expects an array of pointers to scanlines.
* Here the array is only one element long, but you could pass
* more than one scanline at a time if that's more convenient.
*/
row_ptr[0] = &outdata[cinfo.next_scanline * row_stride];
(void) jpeg_write_scanlines(&cinfo, row_ptr, 1);
}
jpeg_finish_compress(&cinfo);
jpeg_destroy_compress(&cinfo);
return true;
}
What is wrong ??
Here is the YUV image
the image file provided (frame-3.raw) is 640x480 in YUYV format
the following code
JSAMPROW row_pointer[1];
row_pointer[0] = row_buf;
while (cinfo.next_scanline < cinfo.image_height) {
unsigned i, j;
unsigned offset = cinfo.next_scanline * cinfo.image_width * 2;
for (i = 0, j = 0; i < cinfo.image_width*2; i += 4, j += 6) {
row_buf[j + 0] = buf[offset + i + 0]; // Y
row_buf[j + 1] = buf[offset + i + 1]; // U
row_buf[j + 2] = buf[offset + i + 3]; // V
row_buf[j + 3] = buf[offset + i + 2]; // Y
row_buf[j + 4] = buf[offset + i + 1]; // U
row_buf[j + 5] = buf[offset + i + 3]; // V
}
jpeg_write_scanlines(&cinfo, row_pointer, 1);
}
to be put in between jpeg_start_compress() and jpeg_finish_compress() creates a JPEG file correctly without color space conversion (but with upsampling)
jason_s's code looks correct as well
I don't think libjpeg will accept subsampled image data as input. So, you'll have to un-subsample it first.
You could allocate a temporary row buffer, and convert each row, something like this:
for (i=0; i<frame->width; i++) {
tmpbuf[i*3+0] = outdata[cinfo.next_scanline * row_stride + i*2];
tmpbuf[i*3+1] = outdata[cinfo.next_scanline * row_stride + (i-i%2)*2+1];
tmpbuf[i*3+2] = outdata[cinfo.next_scanline * row_stride + (i-i%2)*2+3];
}
row_ptr[0] = tmpbuf;