Tracking objects using histogram data in OpenCV - c

I am trying to track objects inside an image using histogram data from the object. I pass in a reference image to get the histogram data and store it in a Mat. From there I load in an image and try and use the histogram data to detect the object. The problem I am coming with is not only is it not tracking the object, but it's not updating the detection. If I load image "1.jpg" the detection will claim that the object is in the top right corner when it's in the bottom left. When I pass in the second image the detection field does not move at all. This continues for the next batch of images as well. Below is a code snippet of my application.
This is being done in a Windows 7 32-bit environment using OpenCV2.3 in VS2010. Thanks in advance for any help
int main( int argc, char** argv )
{
vector<string> szFileNames;
IplImage* Image;
Mat img, hist, backproj;
Rect trackWindow;
// Load histogram data
hist = ImageHistogram("C:/Users/seb/Documents/redbox1.jpg", backproj);
Image = cvLoadImage("C:/Users/seb/Documents/1.jpg");
img = Mat(Image);
trackWindow = Rect(0, 0, Image->width, Image->height);
imshow("Histogram", hist);
while(true)
{
Detection(img, backproj, trackWindow);
imshow("Image", img);
char c = cvWaitKey(1);
switch(c)
{
case 32:
{
cvReleaseImage(&Image);
Image = cvLoadImage("C:/Users/seb/Documents/redbox2.jpg");
img = Mat(Image);
break;
}
}
}
cvReleaseImage(&Image);
// Destroy all windows
cvDestroyWindow("Histogram");
cvDestroyWindow("Image");
return 0;
}
Mat ImageHistogram(string szFilename, Mat& backproj)
{
// Create histogram values
int vmin = 10;
int vmax = 256;
int smin = 30;
int hsize = 16;
float hranges[] = {0,180};
const float* phranges = hranges;
// Load the image
IplImage* Image = cvLoadImage(szFilename.c_str());
Rect rect = Rect(0, 0, Image->width, Image->height);
// Convert Image to a matrix
Mat ImageMat = Mat(Image);
// Create and initialize the Histogram
Mat hsv, mask, hue, hist, histimg = Mat::zeros(200, 320, CV_8UC3);
cvtColor(ImageMat, hsv, CV_BGR2HSV);
// Create and adjust the histogram values
inRange(hsv, Scalar(0, smin, vmin), Scalar(180, 256, vmax), mask);
int ch[] = {0, 0};
hue.create(hsv.size(), hsv.depth());
mixChannels(&hsv, 1, &hue, 1, ch, 1);
Mat roi(hue, rect), maskroi(mask, rect);
calcHist(&roi, 1, 0, maskroi, hist, 1, &hsize, &phranges);
normalize(hist, hist, 0, 255, CV_MINMAX);
histimg = Scalar::all(0);
int binW = histimg.cols / hsize;
Mat buf(1, hsize, CV_8UC3);
for( int i = 0; i < hsize; i++ )
buf.at<Vec3b>(i) = Vec3b(saturate_cast<uchar>(i*180./hsize), 255, 255);
cvtColor(buf, buf, CV_HSV2BGR);
for( int i = 0; i < hsize; i++ )
{
int val = saturate_cast<int>(hist.at<float>(i)*histimg.rows/255);
rectangle( histimg, Point(i*binW,histimg.rows),
Point((i+1)*binW,histimg.rows - val),
Scalar(buf.at<Vec3b>(i)), -1, 8 );
}
calcBackProject(&hue, 1, 0, hist, backproj, &phranges);
backproj &= mask;
cvReleaseImage(&Image);
return histimg;
}
void Detection(Mat& image, Mat& backproj, Rect& trackWindow)
{
RotatedRect trackBox = CamShift(backproj, trackWindow, TermCriteria( CV_TERMCRIT_EPS | CV_TERMCRIT_ITER, 10, 1 ));
int test2 = trackWindow.area();
if(trackBox.size.height > 0 && trackBox.size.width > 0)
{
if( trackWindow.area() <= 1 )
{
int cols = backproj.cols, rows = backproj.rows, r = (MIN(cols, rows) + 5)/6;
trackWindow = Rect(trackWindow.x - r, trackWindow.y - r,
trackWindow.x + r, trackWindow.y + r) &
Rect(0, 0, cols, rows);
}
int test = trackBox.size.area();
if(test >= 1)
{
rectangle(image, trackBox.boundingRect(), Scalar(255,0,0), 3, CV_AA);
ellipse( image, trackBox, Scalar(0,0,255), 3, CV_AA );
}
}
}

I've figured out the issue. It had to deal with me not converting the image that I'm checking upon. I had to get histogram data from my colored box and then I had to get the histogram from the image I was using to search.

Related

Triggering infinite animated objects

I would like to display, in Processing, one photo fading up and fading down over 15 seconds, with a second photo doing the same one second later, and another, etc, ad infinitum.
This example displays 15 objects, but they all start together:
PImage[] imgs = new PImage[42];
int Timer;
Pic[] pics = new Pic[15];
void setup() {
size(1000, 880);
for (int i = 0; i < pics.length; i++) {
pics[i] = new Pic(int(random(0, 29)), random(0, 800), random(0, height));
}
for (int i = 0; i < imgs.length; i++) {
imgs[i] = loadImage(i+".png");
}
}
void draw() {
background(255);
for (int i = 0; i < pics.length; i++) {
pics[i].display();
}
}
class Pic {
float x;
float y;
int num;
int f = 0;
boolean change = true;
Pic(int tempNum, float tempX, float tempY) {
num = tempNum;
x = tempX;
y = tempY;
}
void display() {
imageMode(CENTER);
if (change)f++;
else f--;
if (f==0||f==555)change=!change;
tint(0, 153, 204, f);
image(imgs[num], x, y);
}
}
Thanks!!!
The main issue is you're updating/rendering all images all Pic instances at once. Perhaps you meant to display one at a time (one after the other).
There other sections that raise questions as well:
Timer is never used: it's a good idea to simplify/cleanup code as much as possible
f is used for both the tint alpha (0-255 range) and to fake a delay across multple frames (==555 check)
num is asigned to a random value which means potentially the same pic may be repeated (potentially even consecutively ?) making it hard to notice the effect
I recommend slowing down and breaking the problem down:
fade a single image in and out
determine when a fade in/out cycle is complete
increment a single index (so the next image can fade in and out)
Ideally you want to take the timing (15 seconds into account).
You can work out across how many frames you'd need to fade over 15 seconds. Processing's frameRate property can help with that:
numAlphaSteps = 15 * frameRate;
(e.g. at 60 fps that would be 15 * 60 = 900 frames)
That being said, it takes a few frames for frameRate to "warm up" and become stable. The safer option would be to call frameRate() passing the resired frames per second and reusing that number for the animation
The next step is to map each increment to an alpha value, as it needs to ramp up and back down. You could use a bit of arithmetic.
If you subtract half the number of total fade frames (e.g. 900 / 2 = 450) from each frame number you'd get a value that goes from -half the number of frames to half the number of frames. Here's a minimal sketch you can try out:
int numFrames = 10;
int numFramesHalf = numFrames / 2;
for(int i = 0 ; i < numFrames; i++){
println("frame index", i, "ramp value", i - numFramesHalf);
}
Here's the same, visualised:
background(0);
int numFrames = 10;
int numFramesHalf = numFrames / 2;
for(int i = 0 ; i < numFrames; i++){
int ramp = i - numFramesHalf;
println("frame index", i, "ramp value", ramp);
// visualise numbers
fill(0, 128, 0);
rect(i * 10, 50, 10, map(ramp, 0, 5, 0, 39));
fill(255);
text(i + "\n" + ramp, i * 10, height / 2);
}
(Feel free to change numFrames to 900, 10 is easier to see in console).
If you pass the subtraction result to abs() you'll get positive values:
int numFrames = 10;
int numFramesHalf = numFrames / 2;
for(int i = 0 ; i < numFrames; i++){
println("frame index", i, "ramp value", abs(i - numFramesHalf));
}
and the visualisation:
background(0);
int numFrames = 10;
int numFramesHalf = numFrames / 2;
for(int i = 0 ; i < numFrames; i++){
int ramp = abs(i - numFramesHalf);
println("frame index", i, "ramp value", ramp);
// visualise numbers
fill(0, 128, 0);
rect(i * 10, 0, 10, map(ramp, 0, 5, 0, 39));
fill(255);
text(i + "\n" + ramp, i * 10, height / 2);
}
If you look in Processing Console you should see values that resemble a linear ramp (e.g. large to 0 then back to large).
This is a range that can be easily remapped to a the 0 to 255 range, required for the alpha value, using map(yourValue, inputMinValue, inputMaxValue, outputMinValue, outputMaxValue).
Here's a sketch visualising the tint value going from 0 to 255 and back to 255:
size(255, 255);
int numFrames = 10;
int numFramesHalf = numFrames / 2;
for(int i = 0 ; i <= numFrames; i++){
int frameIndexToTint = abs(i - numFramesHalf);
float tint = map(frameIndexToTint, 0, numFramesHalf, 255, 0);
println("frame index", i, "ramp value", frameIndexToTint, "tint", tint);
rect((width / numFrames) * i, height, 1, -tint);
}
Now with these "ingredients" it should be possible to switch from a for loop draw():
int numFrames = 180;
int numFramesHalf = numFrames / 2;
int frameIndex = 0;
void setup(){
size(255, 255);
}
void draw(){
// increment frame
frameIndex++;
// reset frame
if(frameIndex > numFrames){
frameIndex = 0;
println("fade transition complete");
}
// compute tint
int frameIndexToTint = abs(frameIndex - numFramesHalf);
float tint = map(frameIndexToTint, 0, numFramesHalf, 255, 0);
// visualise tint as background gray
background(tint);
fill(255 - tint);
text(String.format("frameIndex: %d\ntint: %.2f", frameIndex, tint), 10, 15);
}
Notice that using custom index for the transition frame index makes it easy to know when a transition is complete (so it can be reset): this is useful to also increment to the next image:
int numFrames = 180;
int numFramesHalf = numFrames / 2;
int frameIndex = 0;
int imageIndex = 0;
int maxImages = 15;
void setup(){
size(255, 255);
}
void draw(){
// increment frame
frameIndex++;
// reset frame (if larger than transition frames total)
if(frameIndex >= numFrames){
frameIndex = 0;
// increment image index
imageIndex++;
// reset image index (if larger than total images to display)
if(imageIndex >= maxImages){
imageIndex = 0;
}
println("fade transition complete, next image: ", imageIndex);
}
// compute tint
int frameIndexToTint = abs(frameIndex - numFramesHalf);
float tint = map(frameIndexToTint, 0, numFramesHalf, 255, 0);
// visualise tint as background gray
background(tint);
fill(255 - tint);
text(String.format("frameIndex: %d\ntint: %.2f\nimageIndex: %d", frameIndex, tint, imageIndex), 10, 15);
}
These are the main ingredients for your program. You can easily swap the placeholder background drawing with your images:
int numFrames = 180;
int numFramesHalf = numFrames / 2;
int frameIndex = 0;
int imageIndex = 0;
int maxImages = 15;
PImage[] imgs = new PImage[42];
int[] randomImageIndices = new int[maxImages];
void setup(){
size(255, 255);
// load images
for (int i = 0; i < imgs.length; i++) {
imgs[i] = loadImage(i+".png");
}
// pick random images
for (int i = 0; i < maxImages; i++) {
randomImageIndices[i] = int(random(0, 29));
}
}
void draw(){
// increment frame
frameIndex++;
// reset frame (if larger than transition frames total)
if(frameIndex >= numFrames){
frameIndex = 0;
// increment image index
imageIndex++;
// reset image index (if larger than total images to display)
if(imageIndex >= maxImages){
imageIndex = 0;
}
println("fade transition complete, next image: ", imageIndex);
}
// compute tint
int frameIndexToTint = abs(frameIndex - numFramesHalf);
float tint = map(frameIndexToTint, 0, numFramesHalf, 255, 0);
// visualise tint as background gray
background(0);
PImage randomImage =imgs[randomImageIndices[imageIndex]];
tint(255, tint);
image(randomImage, 0, 0);
//debug info
fill(255);
text(String.format("frameIndex: %d\ntint: %.2f\nimageIndex: %d", frameIndex, tint, imageIndex), 10, 15);
}
The x, y position of the image isn't random, but that should be easy to replicated based on how the random image index is used.
Alternatively you can use a single random index and position that get's reset at the end of each transition:
int numFrames = 180;
int numFramesHalf = numFrames / 2;
int frameIndex = 0;
int imageIndex = 0;
int maxImages = 15;
PImage[] imgs = new PImage[42];
int randomImageIndex;
float randomX, randomY;
void setup(){
size(255, 255);
// load images
for (int i = 0; i < imgs.length; i++) {
imgs[i] = loadImage(i+".png");
}
// pick random index
randomImageIndex = int(random(0, 29));
randomX = random(width);
randomY = random(height);
}
void draw(){
// increment frame
frameIndex++;
// reset frame (if larger than transition frames total)
if(frameIndex >= numFrames){
frameIndex = 0;
// increment image index
imageIndex++;
// reset image index (if larger than total images to display)
if(imageIndex >= maxImages){
imageIndex = 0;
}
// reset random values
randomImageIndex = int(random(0, 29));
randomX = random(width);
randomY = random(height);
println("fade transition complete, next image: ", imageIndex);
}
// compute tint
int frameIndexToTint = abs(frameIndex - numFramesHalf);
float tint = map(frameIndexToTint, 0, numFramesHalf, 255, 0);
// visualise tint as background gray
background(0);
PImage randomImage =imgs[randomImageIndex];
tint(255, tint);
image(randomImage, randomX, randomY);
//debug info
fill(255);
text(String.format("frameIndex: %d\ntint: %.2f\nimageIndex: %d", frameIndex, tint, imageIndex), 10, 15);
}
And you can also encapsulate instructions grouped by functionality into functions (removing the redundant imageIndex since we're using a random index):
int numFrames = 180;
int numFramesHalf = numFrames / 2;
int frameIndex = 0;
int imageIndex = 0;
int maxImages = 15;
PImage[] imgs = new PImage[42];
int randomImageIndex;
float randomX, randomY;
void setup(){
size(255, 255);
// load images
for (int i = 0; i < imgs.length; i++) {
imgs[i] = loadImage(i+".png");
}
// pick random index
randomizeImage();
}
void draw(){
updateFrameAndImageIndices();
background(0);
PImage randomImage =imgs[randomImageIndex];
tint(255, tintFromFrameIndex());
image(randomImage, randomX, randomY);
}
float tintFromFrameIndex(){
int frameIndexToTint = abs(frameIndex - numFramesHalf);
return map(frameIndexToTint, 0, numFramesHalf, 255, 0);
}
void updateFrameAndImageIndices(){
// increment frame
frameIndex++;
// reset frame (if larger than transition frames total)
if(frameIndex >= numFrames){
frameIndex = 0;
// increment image index
imageIndex++;
// reset image index (if larger than total images to display)
if(imageIndex >= maxImages){
imageIndex = 0;
}
// reset random values
randomizeImage();
println("fade transition complete, next image: ", imageIndex);
}
}
void randomizeImage(){
randomImageIndex = int(random(0, 29));
randomX = random(width);
randomY = random(height);
}
If the goal of this coding excecise is to practice using classes, you can easily further encapsulate the image fade related functions and variables into a class:
PImage[] imgs = new PImage[42];
ImagesFader fader;
void setup(){
size(255, 255);
frameRate(60);
// load images
for (int i = 0; i < imgs.length; i++) {
imgs[i] = loadImage(i+".png");
}
// setup fader instance
// constructor args: PImage[] images, float transitionDurationSeconds, int frameRate
// use imgs as the images array, transition in and out within 1s per image at 60 frames per second
fader = new ImagesFader(imgs, 1.0, 60);
}
void draw(){
background(0);
fader.draw();
}
class ImagesFader{
int numFrames;
int numFramesHalf;
int frameIndex = 0;
PImage[] images;
int maxImages = 15;
int randomImageIndex;
float randomX, randomY;
ImagesFader(PImage[] images, float transitionDurationSeconds, int frameRate){
numFrames = (int)(frameRate * transitionDurationSeconds);
numFramesHalf = numFrames / 2;
println(numFrames);
this.images = images;
// safety check: ensure maxImage index isn't larger than the total number of images
maxImages = min(maxImages, images.length - 1);
// pick random index
randomizeImage();
}
void draw(){
updateFrameAndImageIndices();
PImage randomImage = imgs[randomImageIndex];
// isolate drawing style (so only the image fades, not everything in the sketch)
pushStyle();
tint(255, tintFromFrameIndex());
image(randomImage, randomX, randomY);
popStyle();
}
float tintFromFrameIndex(){
int frameIndexToTint = abs(frameIndex - numFramesHalf);
return map(frameIndexToTint, 0, numFramesHalf, 255, 0);
}
void updateFrameAndImageIndices(){
// increment frame
frameIndex++;
// reset frame (if larger than transition frames total)
if(frameIndex >= numFrames){
frameIndex = 0;
// randomize index and position
randomizeImage();
println("fade transition complete, next image: ", randomImageIndex);
}
}
void randomizeImage(){
randomImageIndex = int(random(0, 29));
randomX = random(width);
randomY = random(height);
}
}
If you're comfortable using Processing libraries, you can achieve the same with a tweening library like Ani:
import de.looksgood.ani.*;
import de.looksgood.ani.easing.*;
PImage[] imgs = new PImage[42];
float tintValue;
int randomImageIndex;
float randomX, randomY;
AniSequence fadeInOut;
void setup(){
size(255, 255);
frameRate(60);
// load images
for (int i = 0; i < imgs.length; i++) {
imgs[i] = loadImage(i+".png");
}
randomizeImage();
// Ani.init() must be called always first!
Ani.init(this);
// create a sequence
// dont forget to call beginSequence() and endSequence()
fadeInOut = new AniSequence(this);
fadeInOut.beginSequence();
// fade in
fadeInOut.add(Ani.to(this, 0.5, "tintValue", 255));
// fade out (and call sequenceEnd() when on completion)
fadeInOut.add(Ani.to(this, 0.5, "tintValue", 0, Ani.QUAD_OUT, "onEnd:sequenceEnd"));
fadeInOut.endSequence();
// start the whole sequence
fadeInOut.start();
}
void draw(){
background(0);
tint(255, tintValue);
image(imgs[randomImageIndex], randomX, randomY);
}
void sequenceEnd() {
randomizeImage();
fadeInOut.start();
}
void randomizeImage(){
randomImageIndex = int(random(0, 29));
randomX = random(width);
randomY = random(height);
}
Update Based on your comment regarding loading images, can you try this sketch ?
void setup(){
size(1000, 500);
textAlign(CENTER);
PImage[] images = loadImages("Data","png");
int w = 100;
int h = 100;
for(int i = 0; i < images.length; i++){
float x = i % 10 * w;
float y = i / 10 * h;
image(images[i], x, y, w, h);
text("["+i+"]",x + w / 2, y + h / 2);
}
}
PImage[] loadImages(String dir, String extension){
String[] files = listPaths(dir, "files", "extension=" + extension);
int numFiles = files.length;
PImage[] images = new PImage[numFiles];
for(int i = 0 ; i < numFiles; i++){
images[i] = loadImage(files[i]);
}
return images;
}
It should load images in the "Data" folder (as the comment mentions, not "data" which is commonly used in Processing). If "Data" is a typo, fix the path first (as Processing is key sensitive ("Data" != "data")). If the 50 images load correctly, it should display in a 10x5 grid at 100x100 px each (e.g. disregarding each image's aspect ratio). This should help test if the images load correctly. (Again, breaking the problem down to individual steps).

how to create bitmap in C and compile with gcc

i decided to learn C, and i try to follow this tutorial http://ricardolovelace.com/creating-bitmap-images-with-c-on-windows.html
but when i try to compile my code with gcc as this >gcc -Wall testc o app
he doesn't know type_rgb, can i define this type and how? and where in my code ?
#include <stdio.h>
struct rgb_data {
float r, g, b;
};
void save_bitmap( const char *file_name, int width, int height, int dpi, type_rgb *pixel_data);
/*
next steps of the tutorial
*/
rgb_data *pixels = new rgb_data[width * height];
for( int x = 0; x < width; x++)
{
for(int y = 0; y < height; y++)
int a = y * width +x;
{
if ((x > 50 && x < 350) && (y > y && y < 350))
{
pixels[a].r = 255;
pixels[a].g = 255;
pixels[a].b = 0;
}else{
pixels[a].r = 55;
pixels[a].g = 55;
pixels[a].b = 55;
}
}
}
save_bitmap("black_border.bmp", width, height, dpi, pixels);
Bitmap file format is rather complicated. This is not the best way to learn C. It's better to start with something much simpler.
Having said that, the bitmap format starts with a bitmap header BITMAPFILEHEADER structure which is 14 bytes long, followed by BITMAPINFOHEADER structure 40 bytes long. These structures are defined in "Windows.h"
You have to write in various information in these structures and write them to file before writing the actual pixels.
You can have 1, 4, 8, 16, 24, and 32-bit bitmap. This is an example to read a 32-bit bitmap. This code assumes sizeof(short) is 2, sizeof(int) is 4.
int main()
{
int row, column;
int width = 100;
int height = 100;
int size = width * height * 4; //for 32-bit bitmap only
char header[54] = { 0 };
strcpy(header, "BM");
memset(&header[2], (int)(54 + size), 1);
memset(&header[10], (int)54, 1);//always 54
memset(&header[14], (int)40, 1);//always 40
memset(&header[18], (int)width, 1);
memset(&header[22], (int)height, 1);
memset(&header[26], (short)1, 1);
memset(&header[28], (short)32, 1);//32bit
memset(&header[34], (int)size, 1);//pixel size
unsigned char *pixels = malloc(size);
for(row = height - 1; row >= 0; row--) {
for(column = 0; column < width; column++) {
int p = (row * width + column) * 4;
pixels[p + 0] = 64; //blue
pixels[p + 1] = 128;//green
pixels[p + 2] = 192;//red
}
}
FILE *fout = fopen("32bit.bmp", "wb");
fwrite(header, 1, 54, fout);
fwrite(pixels, 1, size, fout);
free(pixels);
fclose(fout);
return 0;
}
Note the first pixel is blue, followed by green and read. The last pixel is not used in 32-bit bitmap. Also the height goes from bottom to top. This is another odd feature of bitmap. 24-bit bitmaps are more complicated because they need padding. 8-bit and lower will need an additional palette.
struct rgb_data {
float r, g, b;
};
float is not the right type for pixels. Each color goes from 0 to 255. This fits in unsigned char. You need instead
struct rgb_data {
unsigned r, g, b, alpha;
};
The alpha is the extra byte for 32-bit bitmap (which we won't use). Notice the size of this structure is 4. You can allocate this as
struct rgb_data *rgb = malloc(size);
Now you can access the pixels as follows:
int p = (row * width + column);
rgb[p].r = 255;
rgb[p].g = 0;
rgb[p].b = 0;
...
fwrite(rgb, 4, width * height, fout);

Weird Runtime Inconsistent Behaviour While Writing Bitmap Bytes To Binary File

I have written a primitive Bitmap Writer, that prepares a bitmap header, calculates a data section and write it as binary file.
The problem is, the program working for 800x600 resolution however, not working for some arbitrary resolution.
Bitmap Writer Code
#include <stdio.h>
#include <stdlib.h> // malloc()
#include <string.h>
/*
* File Write , check this link : https://www.codingunit.com/c-tutorial-binary-file-io
*
*/
typedef enum { FALSE, TRUE } boolean;
/* For 54 byte header data
*
* http://blog.paphus.com/blog/2012/08/14/write-your-own-bitmaps/
*/
#pragma pack(push,1)
typedef struct BitmapHeaderType {
unsigned char b0; // 0
unsigned char b1; // 1
unsigned int fullFileSize; // 2...5
unsigned int reserved; // 6...9
unsigned int pixelOffset; // 10..13 HEADER SIZE
unsigned int bitmapInfoHeaderSize; // 14..17 BITMAP INFO HEADER SIZE
unsigned int pixelWidth; // 18..21 image width
unsigned int pixelHeight; // 22..25 image height
unsigned short int numberOfColorPlanes; // 26..27 the number of color planes
unsigned short int bitPerPixel; // 28..29 24bit, 32bit, bit size
unsigned int compessionState; // 30..33 compression state, 0 for disable compression
unsigned int sizeOfRawPixel; // 34..37 size of pixel data including paddings (24 bit padding changes data section)
unsigned int horizontalResolution; // 38..41 just leave 2835
unsigned int verticalResolution; // 42..45 just leave 2835
unsigned int numberOfColors; // 46..49 set 0 for default
unsigned int numberOfImportantColors; // 50..53 set 0 for default
} BitmapHeader;
#pragma pack(pop)
void handleBitmapHeader(BitmapHeader *header, int width, int height);
int closestMultipleOfFour(int num);
void writeToFile(unsigned char* bytes, int len, char fileName[]);
void setPixel(unsigned char *data, int x, int y, unsigned char red, unsigned char green, unsigned char blue, int width, int height);
int main()
{
//int width = 800; // compiling OK, runtime OK
int width = 100; // compiling OK, runtime FAILED
int height = 600;
BitmapHeader *header = (BitmapHeader *)malloc(sizeof(BitmapHeader));
handleBitmapHeader(header, width, height);
unsigned char *data = (unsigned char *)malloc(header->sizeOfRawPixel);
unsigned char *bitmap = (unsigned char *)malloc(header->fullFileSize);
// left top corner
setPixel(data, 0 , 0 , 255, 0, 0, width, height);
setPixel(data, 0 , 1 , 255, 0, 0, width, height);
setPixel(data, 1 , 0 , 255, 0, 0, width, height);
setPixel(data, 1 , 1 , 255, 0, 0, width, height);
// right top corner
setPixel(data, width-1 , 0 , 255, 0, 0, width, height);
setPixel(data, width-1 , 1 , 255, 0, 0, width, height);
setPixel(data, width-2 , 0 , 255, 0, 0, width, height);
setPixel(data, width-2 , 1 , 255, 0, 0, width, height);
// left bottom corner
setPixel(data, 0 , height-1 , 255, 0, 0, width, height);
setPixel(data, 0 , height-2 , 255, 0, 0, width, height);
setPixel(data, 1 , height-1 , 255, 0, 0, width, height);
setPixel(data, 1 , height-2 , 255, 0, 0, width, height);
// right bottom corner
setPixel(data, width-1 , height-1 , 255, 0, 0, width, height);
setPixel(data, width-1 , height-2 , 255, 0, 0, width, height);
setPixel(data, width-2 , height-1 , 255, 0, 0, width, height);
setPixel(data, width-2 , height-2 , 255, 0, 0, width, height);
// copy header to bitmap
memcpy(bitmap, header, header->pixelOffset);
// copy data to bitmap
memcpy(bitmap+header->pixelOffset, data, header->fullFileSize);
char fileName[] = "sampleBitmap.bmp";
// write
writeToFile((unsigned char *)bitmap , header->fullFileSize, fileName);
free(header);
free(data);
free(bitmap);
return 0;
}
void handleBitmapHeader(BitmapHeader *header, int width, int height)
{
// Calculate row with padding
int rowWithPadding = closestMultipleOfFour(width*3);
int rawSize = height * rowWithPadding;
printf("Row With Padding : %4d\n", rowWithPadding);
printf("Raw Size : Decimal[%4d], Hex[%4x]\n", rawSize, rawSize);
header->b0 = 'B';
header->b1 = 'M';
header->fullFileSize = rawSize + 54;
header->reserved = 0x00000000;
header->pixelOffset = 54;
header->bitmapInfoHeaderSize = 40;
header->pixelWidth = (unsigned int)width;
header->pixelHeight = (unsigned int)height;
header->numberOfColorPlanes = 1;
header->bitPerPixel = 24;
header->compessionState = 0;
header->sizeOfRawPixel = (unsigned int) rawSize;
header->horizontalResolution = 0x2835;
header->verticalResolution = 0x2835;
header->numberOfColors = 0;
header->numberOfImportantColors = 0;
}
int closestMultipleOfFour(int num)
{
return (num + 3) & ~0x03;
}
void writeToFile(unsigned char* bytes, int len, char fileName[])
{
FILE *filePtr;
printf("HIT A : len = %d\n", len);
filePtr = fopen(fileName, "wb"); // wb for write binary
printf("HIT B\n");
if(!filePtr)
{
printf("ERROR::writeToFile()::Unable to open file : \"%s\"\n", fileName);
return;
}
fwrite(bytes, len, 1, filePtr);
fclose(filePtr);
}
void setPixel(unsigned char *data, int x, int y, unsigned char red, unsigned char green, unsigned char blue, int width, int height)
{
y = height-1-y;
int index = 0;
int padSize = 0;
if(x < width && y == 0) // no need to calculate padding
index = x * 3;
else
{
boolean isPadding = ( (width*3) % 4 == 0) ? FALSE : TRUE;
if(isPadding == TRUE) {
padSize = closestMultipleOfFour(width * 3);
} else {
index = (y*width + x)*3;
}
}
int bytes = 0;
*(data + index+padSize + bytes++) = blue;
*(data + index+padSize + bytes++) = green;
*(data + index+padSize + bytes) = red;
}
Please notify the lines below;
//int width = 800; // compiling OK, runtime OK
int width = 100; // compiling OK, runtime FAILED
int height = 600;
If you just run for 800x600 resolution like;
int width = 800; // compiling OK, runtime OK
/int width = 100; // compiling OK, runtime FAILED
int height = 600;
The program runs sucessfully. And also notify that for both conditions, the program is compiling successfully.
I try with gcc and MS VS, the behaviour is the same for both resolutions.
I've also tried to debug the program with MS VS but while debugging, the program triggered a breakpoint then directly ask me for a dll (I'm not expert on MS VS Debugging with C)
It seems the problematic part is with this line where exist in writeToFile() function;
filePtr = fopen(fileName, "wb"); // wb for write binary
Any ideas on where do I've gone wrong ?
The program crashed because this line is accessing the memory out of bound:
memcpy(bitmap + header->pixelOffset, data, header->fullFileSize);
I think what you need is
memcpy(bitmap + header->pixelOffset, data, header->sizeOfRawPixel);
because bitmap is a buffer contains the header and the raw data.

How to find corner coordinates of Image contour in Opencv and C

I have to find corner points of an image so that I can crop it in rectangular shape.I have already found the contour and used approxpoly() function on it.Now how to find the corner Co-ordinates of the contour ?
Here is my C code->
#include <cv.h>
#include <highgui.h>
int main(int argc, char** argv)
{
IplImage *img,*gray;
if((img = cvLoadImage("save.jpg", 1)) == NULL)
{
printf("A Img open error\n");
}
gray=cvCreateImage( cvGetSize(img), IPL_DEPTH_8U, 1 );
cvCvtColor(img,gray,CV_BGR2GRAY);
IplImage* out_median = cvCreateImage(cvGetSize(gray),IPL_DEPTH_8U,1);
cvSmooth( gray,out_median,CV_MEDIAN,3);
IplImage* out_threshold = cvCreateImage( cvGetSize(out_median), out_median->depth, 1);
cvThreshold(out_median,out_threshold,1,255,CV_THRESH_BINARY);
CvMemStorage* storage = cvCreateMemStorage();
CvSeq* first_contour = NULL;
cvFindContours(out_threshold,storage,&first_contour,sizeof(CvContour),CV_RETR_LIST,CV_CHAIN_APPROX_SIMPLE);
CvSeq* approx_polygon = NULL;
approx_polygon=cvApproxPoly(first_contour,sizeof(CvContour),storage,CV_POLY_APPROX_DP,0.01*cvArcLength(first_contour,CV_WHOLE_SEQ, 1),0);
//cvDrawContours(out_threshold,approx_polygon,cvScalarAll(255),cvScalarAll(255),100);
//cvShowImage("Contours", out_threshold );
//cvSaveImage("save_approxpoly_contour.jpg",out_threshold);
cvWaitKey(0);
return 0;
}
This my Contour Image after applying the Approxpoly()
I recommend using cvBlob:
Get the blobs:
cvThreshold(&src, &dst, 10, 255, CV_THRESH_BINARY);
IplImage *labelImg = cvCreateImage(cvGetSize(&dst),IPL_DEPTH_LABEL,1);
CvBlobs blobs;
unsigned int result = cvLabel(&dst, labelImg, blobs);
If you have more than one item, find the limits
int borders[4];
borders[0] = 99999; //left
borders[1] = 99999; //top
borders[2] = 0; //right
borders[3] = 0; //bottom
for (CvBlobs::const_iterator it=blobs.begin(); it!=blobs.end(); ++it)
{
if((*it).second->maxx) < borders[0]){
borders[0] = (*it).second->maxx;
}
if(((*it).second->miny) < borders[1]){
borders[1] = (*it).second->miny;
}
if((*it).second->minx) > borders[2]){
borders[2] = (*it).second->minx;
}
if(((*it).second->maxy) > borders[3]){
borders[3] = (*it).second->maxy;
}
}

How would one draw to the sub display of a ds as if it was a framebuffer?

I need to draw raw pixel data to the Nintendo DS's "sub" screen, such as if I was drawing to the main screen in "framebuffer" mode or "Extended Rotation" mode. How can I do this with the current version of libnds (which seems to place restrictions on the use of VRAM_C)?
#include <nds.h>
int main(void)
{
int x, y;
//set the mode to allow for an extended rotation background
videoSetMode(MODE_5_2D);
videoSetModeSub(MODE_5_2D);
//allocate a vram bank for each display
vramSetBankA(VRAM_A_MAIN_BG);
vramSetBankC(VRAM_C_SUB_BG);
//create a background on each display
int bgMain = bgInit(3, BgType_Bmp16, BgSize_B16_256x256, 0,0);
int bgSub = bgInitSub(3, BgType_Bmp16, BgSize_B16_256x256, 0,0);
u16* videoMemoryMain = bgGetGfxPtr(bgMain);
u16* videoMemorySub = bgGetGfxPtr(bgSub);
//initialize it with a color
for(x = 0; x < 256; x++)
for(y = 0; y < 256; y++)
{
videoMemoryMain[x + y * 256] = ARGB16(1, 31, 0, 0);
videoMemorySub[x + y * 256] = ARGB16(1, 0, 0, 31);
}
while(1)
{
swiWaitForVBlank();
}
}
Here is a simple example which creates a 16 bit frame buffer on the main and sub screens and fills each with either red or blue.

Resources