How to decode an animated gif File in MFC2010 - c++

Deal all,
I need to decode an animated gif format picture into some bitmap files in MFC2010. Is there any library to decode a gif picture? I cannot use GDIPlus because the program has to run on windows XP. I do appreciate if someone provides me with a library, Activex, dll or anything similar.
Many Thanks,
Shervin Zargham

It's pretty simple using ImageMagick's C++ API (Magick++) :
/* list of Image to store the GIF's frames */
std::vector<Magick::Image> imageList;
/* read all the frames of the animated GIF */
Magick::readImages( &imageList, "animated.gif" );
/* optionnally coalesce the frame sequence depending on the expected result */
Magick::coalesceImages( &imageList, imageList.begin(), imageList.end());
/* store each frame in a separate BMP file */
for(unsigned int i = 0; i < imageList.size(); ++i) {
std::stringstream ss;
ss << "frame" << i << ".bmp";
imageList[i].write(ss.str());
}

WIC (included in Vista, available for XP) offers CLSID_WICGifDecoder, a COM component.

Try this using ImageMagick's C++ API (Magick++) ,tested on VS210:
#include <Magick++.h>
#include <string>
#include <iostream>
#include <list>
using namespace std;
using namespace Magick;
void kk(char * nombre, char *ext)
{
/* list of Image to store the GIF's frames */
std::list<Magick::Image> imageList;
/* read all the frames of the animated GIF */
Magick::readImages( &imageList, nombre );
/* compone las diferencias para obtener los cuadros reales */
Magick::coalesceImages(&imageList,imageList.begin( ),imageList.end( ));
/* store each frame in a separate BMP file */
list <Magick::Image>::iterator it;
int i=1;
for ( it = imageList.begin( ); it != imageList.end( ); it++ , i++)
{
std::string name = "frame" + to_string((_Longlong)(i)) + ext ;
it->write(name);
}
}
int main( int /*argc*/, char ** argv)
{
// Initialize ImageMagick install location for Windows
InitializeMagick(*argv);
try {
kk("luni0.gif", ".png"); // using ".bmp", ".jpg", ".png", OK
return 0;
}
catch( exception &error_ )
{
cout << "Caught exception: " << error_.what() << endl;
return 1;
}
}

It's been a long time, but I recall once using OleLoadPicture to open GIF and PNG files on old versions of Windows, though the documentation seems to suggest that it's only for BMP, ICO, and WMF.

Related

Convert C-Source image dump into original image

I have created with GIMP a C-Source image dump like the following:
/* GIMP RGBA C-Source image dump (example.c) */
static const struct {
guint width;
guint height;
guint bytes_per_pixel; /* 2:RGB16, 3:RGB, 4:RGBA */
guint8 pixel_data[304 * 98 * 2 + 1];
} example= {
304, 98, 2,
"\206\061\206\061..... }
Is there a way to read this in GIMP again in order to get back the original image? because it doesn't seem possible.
Or does it exist a tool that can do this back-conversion?
EDITED
Following some suggestion I tried to write a simple C programme to make the reverse coversion ending up with something very similar to another code found on internet but both dont work:
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "imgs_press.h"
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
using namespace std;
int main(int argc, char** argv) {
int fd;
char *name = "orignal_img.pnm";
fd = open(name, O_WRONLY | O_CREAT, 0644);
if (fd == -1) {
perror("open failed");
exit(1);
}
if (dup2(fd, 1) == -1) {
perror("dup2 failed");
exit(1);
}
// file descriptor 1, i.e. stdout, now points to the file
// "helloworld" which is open for writing
// You can now use printf which writes specifically to stdout
printf("P2\n");
printf("%d %d\n", press_high.width, press_high.height);
for(int x=0; x<press_high.width * press_high.height * 2; x++) {
printf("%d ", press_high.pixel_data[x]);
}
}
As suggested by n-1-8e9-wheres-my-share-m, maybe I need to manipulate the pixels usign the correct decode, but I have no idea how to do that, does anybody have other suggestions?
The image I got is indeed distorted:
Updated Answer
If you want to decode the RGB565 and write a NetPBM format PNM file without using ImageMagick, you can do this:
#include <stdint.h> /* for uint8_t */
#include <stdio.h> /* for printf */
/* tell compiler what those GIMP types are */
typedef int guint;
typedef uint8_t guint8;
#include <YOURGIMPIMAGE>
int main(){
int w = gimp_image.width;
int h = gimp_image.height;
int i;
uint16_t* RGB565p = (uint16_t*)&(gimp_image.pixel_data);
/* Print P3 PNM header on stdout */
printf("P3\n%d %d\n255\n",w, h);
/* Print RGB pixels, ASCII, one RGB pixel per line */
for(i=0;i<w*h;i++){
uint16_t RGB565 = *RGB565p++;
uint8_t r = (RGB565 & 0xf800) >> 8;
uint8_t g = (RGB565 & 0x07e0) >> 3;
uint8_t b = (RGB565 & 0x001f) << 3;
printf("%d %d %d\n", r, g ,b);
}
}
Compile with:
clang example.c
And run with:
./a.out > result.pnm
I have not tested it too extensively beyond your sample image, so you may want to make a test image with some reds, greens, blues and shades of grey to ensure that all my bit-twiddling is correct.
Original Answer
The easiest way to get your image back would be... to let ImageMagick do it.
So, take your C file and add a main() to it that simply writes the 304x98x2 bytes starting at &(example.pixel_data) to stdout:
Compile it with something like:
clang example.c -o program # or with GCC
gcc example.c -o program
Then run it, writing to a file for ImageMagick with:
./program > image.bin
And tell ImageMagick its size, type and where it is and what you want as a result:
magick -size 304x98 RGB565:image.bin result.png
I did a quick, not-too-thorough test of the following code and it worked fine for an image I generated with GIMP. Note it doesn't handle alpha/transparency but that could be added if necessary. Save it as program.c:
#include <unistd.h> /* for write() */
#include <stdint.h> /* for uint8_t */
/* tell compiler what those GIMP types are */
typedef int guint;
typedef uint8_t guint8;
<PASTE YOUR GIMP FILE HERE>
int main(){
/* Work out how many bytes to write */
int nbytes = example.width * example.height * 2;
/* Write on stdout for redirection to a file - may need to reopen in binary mode if on Windows */
write(1, &(example.pixel_data), nbytes);
}
If I run this with the file you provided via Google Drive I get:

How to configure c++ Zbar scanner to decode only QR-Code data type?

I am using Zbar C++ library to decode QRCode,using this tutorial:
https://www.learnopencv.com/barcode-and-qr-code-scanner-using-zbar-and-opencv/
Here I have to decode only QRCode from an image however using this tutorial it decodes both QRcode and barcodes from an Image.
In tutorial it says to decode only QRCode we have to Configure Zbar Imagescanner properly.
In tutorial they are using following configuration to decode both QRCode and Barcodes
ImageScanner scanner;
scanner.set_config(ZBAR_NONE, ZBAR_CFG_ENABLE, 1);
So to decode only QRCode I am using following configuration:
ImageScanner scanner;
scanner.set_config(ZBAR_QRCODE, ZBAR_CFG_ENABLE, 1);
But using this Zbar configuration still it decodes both QRCode and barcodes data.I am getting Decoded Data type as EAN-13 and QR-Code.
How I can configure Zbar sccanner properly so it decodes only QR-Code Data type?
//Reference:https://www.learnopencv.com/opencv-qr-code-scanner-c-and-python/
#include <iostream>
#include <algorithm>
#include <vector>
#include <zbar.h>
#include <opencv2/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace std;
using namespace cv;
using namespace zbar;
typedef struct
{
string type;
string data;
vector <Point> location;
}decodedObject;
// Find and decode barcodes and QR codes
void decode(Mat &im, vector<decodedObject>&decodedObjects)
{
// Create zbar scanner
ImageScanner scanner;
// Configure scanner
scanner.set_config(ZBAR_QRCODE, ZBAR_CFG_ENABLE, 1);
// Convert image to grayscale
Mat imGray;
cvtColor(im, imGray,CV_BGR2GRAY);
// Wrap image data in a zbar image
Image image(im.cols, im.rows, "Y800", (uchar *)imGray.data, im.cols * im.rows);
// Scan the image for barcodes and QRCodes
int n = scanner.scan(image);
// Print results
for(Image::SymbolIterator symbol = image.symbol_begin(); symbol != image.symbol_end(); ++symbol)
{
decodedObject obj;
obj.type = symbol->get_type_name();
obj.data = symbol->get_data();
// Print type and data
cout << "Type : " << obj.type << endl;
cout << "Data : " << obj.data << endl << endl;
decodedObjects.push_back(obj);
}
}
int main(int argc, char *argv[])
{
// Read image
string imagepath = argv[1];
Mat im = imread(imagepath);
// Variable for decoded objects
vector<decodedObject> decodedObjects;
// Find and decode barcodes and QR codes
decode(im, decodedObjects);
return 0;
}
Resulted Output:
Type : QR-Code
Data : http://LearnOpenCV.com
Type : EAN-13
Data : 0036000291452
Expected Output:
Type : QR-Code
Data : http://LearnOpenCV.com
I assume you need to disable all first with
// disable all
scanner.set_config(ZBAR_NONE, ZBAR_CFG_ENABLE, 0);
// enable qr
scanner.set_config(ZBAR_QRCODE, ZBAR_CFG_ENABLE, 1);

How to give folder of images as input to Magick++ api?

I am need of passing a folder of images as input to Magick++ api. It can be done using mogrify in commandline as shown in post "ImageMagick script to resize folder of images". Reading a single image could be done through api call as
Image image(inputimage)
But how could we do the same for a folder of images? Can anyone help me with the respective api call?
That feature is not included in the Magick++ API. You will need to iterate the directory yourself and then use the Magick++ API to read and write the image. You can find an example on how to iterate through a folder in C/C++ in the following Stack Overflow post: How can I get the list of files in a directory using C or C++?.
I believe you would be responsible of reading the directory. The C library dirent.h is the first thing I think of, but I'm sure there's better C++/system/framework techniques.
#include <iostream>
#include <vector>
#include <dirent.h>
#include <Magick++.h>
int main(int argc, const char * argv[]) {
std::vector<Magick::Image> stack; // Hold images found
DIR * dir_handler = opendir("/tmp/images"); // Open dir
struct dirent * dir_entry;
if (dir_handler != NULL)
{
// Iterate over entries in directory
while ( (dir_entry = readdir(dir_handler)) != NULL ) {
// Only act on regular files
if (dir_entry->d_type == DT_REG) {
// Concatenate path (could be better)
std::string filename("/tmp/images/");
filename += dir_entry->d_name;
// Read image at path
stack.push_back(Magick::Image(filename));
}
}
closedir(dir_handler); // House keeping
} else {
// Handle DIR error
}
// Append all images into single montage
Magick::Image output;
Magick::appendImages(&output, stack.begin(), stack.end());
output.write("/tmp/all.png");
return 0;
}
There's also ExpandFilenames(int *,char ***) in the MagickCore library.
// Patterns to scan
int pattern_count = 1;
// First pattern
char pattern[PATH_MAX] = "/tmp/images/*.png";
// Allocate memory for list of patterns
char ** dir_pattern = (char **)MagickCore::AcquireMagickMemory(sizeof(char *));
// Assign first pattern
dir_pattern[0] = pattern;
// Expand patterns
Magick::MagickBooleanType ok;
ok = MagickCore::ExpandFilenames(&pattern_count, &dir_pattern);
if (ok == Magick::MagickTrue) {
std::vector<Magick::Image> stack;
// `pattern_count' now holds results count
for ( int i = 0; i < pattern_count; ++i) {
// `dir_pattern' has been re-allocated with found results
std::string filename(dir_pattern[i]);
stack.push_back(Magick::Image(filename));
}
Magick::Image output;
Magick::appendImages(&output, stack.begin(), stack.end());
output.write("/tmp/all.png");
} else {
// Error handle
}

VideoCapture not working C++ windows

So I have played around in OpenCV a bunch before and never run into this problem. I am implementing a MeanShift algorithm and trying to do it on video devices, images, and videos. Devices and images work; however, no matter what I try, when I run VideoCapture on my filename (whether setting it in the Constructor or using the VideoCapture::open() method, and whether local or with a full path) I always get stuck in my error check.
Thoughts? Ideas? code below. running in Visual Studio 2012
#include "opencv2\highgui\highgui.hpp"
#include "opencv2\core\core.hpp"
#include "opencv2\opencv.hpp"
#include "opencv2\video\video.hpp"
#include <string>
using cv::Mat;
using std::string;
enum Filetype{Image, Video};
int main(int argc, char* argv[])
{
string filename = "short_front.avi";// "C:\\Users\\Jonathan\\Videos\\short_front.mp4"; //"hallways.jpg";
Mat cv_image; //convert to unsigned char * with data
Mat filtImage_;
Mat segmImage_;
Mat whiteImage_;
cv::VideoCapture vid;
vid.open("C:/Users/Jonathan/Desktop/TestMeanShift/TestMeanShift/short_front.avi");
cv::waitKey(1000);
if ( !vid.isOpened() ){
throw "Error when reading vid";
cv::waitKey(0);
return -1;
}
// cv_image = cv::imread(filename);//, CV_LOAD_IMAGE_COLOR);
// if(! cv_image.data){
// std::cerr << "Image Failure: " << std::endl;
// system("pause");
// return -1;
// }
//Mat cv_image_gray;
//cv::cvtColor(cv_image,cv_image_gray,CV_RGB2GRAY);
for (;;)
{
vid >> cv_image;
if ( !cv_image.data)
continue;
cv::imshow("Input",cv_image); //add a normal window here to resizable
}
EDIT: This is a distinct problem from the one listed here because it deals with a specific corner case: VideoCapture and ImageCapture both work, only not VideoCapture with a file. When it doesn't work, the code runs properly, except that the "video" it creates is incomplete as it didn't open properly. Therefore, as the code above does not crash in compile time or run time, the only indicator is bad output (6KB video output file). If you are having issues not with the corner case I am describing but general issues with the above functions in OpenCV, the aforementioned link could help you.

Object Marking in Haar training

I am doing a project on object detection in OpenCV using haar training. I have to mark, in an image, all the places where the object is present. So, I need a code which opens each image so that I can mark the regions.
Similar to the one here:
#include <opencv/cv.h>
#include <opencv/cvaux.h>
#include <opencv/highgui.h>
// for filelisting
#include <stdio.h>
#include <sys/io.h>
// for fileoutput
#include <string>
#include <fstream>
#include <sstream>
#include <dirent.h>
#include <sys/types.h>
using namespace std;
IplImage* image=0;
IplImage* image2=0;
//int start_roi=0;
int roi_x0=0;
int roi_y0=0;
int roi_x1=0;
int roi_y1=0;
int numOfRec=0;
int startDraw = 0;
char* window_name="<SPACE>add <B>save and load next <ESC>exit";
string IntToString(int num)
{
ostringstream myStream; //creates an ostringstream object
myStream << num << flush;
/*
* outputs the number into the string stream and then flushes
* the buffer (makes sure the output is put into the stream)
*/
return(myStream.str()); //returns the string form of the stringstream object
};
void on_mouse(int event,int x,int y,int flag, void *param)
{
if(event==CV_EVENT_LBUTTONDOWN)
{
if(!startDraw)
{
roi_x0=x;
roi_y0=y;
startDraw = 1;
} else {
roi_x1=x;
roi_y1=y;
startDraw = 0;
}
}
if(event==CV_EVENT_MOUSEMOVE && startDraw)
{
//redraw ROI selection
image2=cvCloneImage(image);
cvRectangle(image2,cvPoint(roi_x0,roi_y0),cvPoint(x,y),CV_RGB(255,0,255),1);
cvShowImage(window_name,image2);
cvReleaseImage(&image2);
}
}
int main(int argc, char** argv)
{
char iKey=0;
string strPrefix;
string strPostfix;
string input_directory;
string output_file;
if(argc != 3) {
fprintf(stderr, "%s output_info.txt raw/data/directory/\n", argv[0]);
return -1;
}
input_directory = argv[2];
output_file = argv[1];
/* Get a file listing of all files with in the input directory */
DIR *dir_p = opendir (input_directory.c_str());
struct dirent *dir_entry_p;
if(dir_p == NULL) {
fprintf(stderr, "Failed to open directory %s\n", input_directory.c_str());
return -1;
}
fprintf(stderr, "Object Marker: Input Directory: %s Output File: %s\n", input_directory.c_str(), output_file.c_str());
// init highgui
cvAddSearchPath(input_directory);
cvNamedWindow(window_name,1);
cvSetMouseCallback(window_name,on_mouse, NULL);
fprintf(stderr, "Opening directory...");
// init output of rectangles to the info file
ofstream output(output_file.c_str());
fprintf(stderr, "done.\n");
while((dir_entry_p = readdir(dir_p)) != NULL)
{
numOfRec=0;
if(strcmp(dir_entry_p->d_name, ""))
fprintf(stderr, "Examining file %s\n", dir_entry_p->d_name);
/* TODO: Assign postfix/prefix info */
strPostfix="";
//strPrefix=input_directory;
strPrefix=dir_entry_p->d_name;
//strPrefix+=bmp_file.name;
fprintf(stderr, "Loading image %s\n", strPrefix.c_str());
if((image=cvLoadImage(strPrefix.c_str(),1)) != 0)
{
// work on current image
do
{
cvShowImage(window_name,image);
// used cvWaitKey returns:
// <B>=66 save added rectangles and show next image
// <ESC>=27 exit program
// <Space>=32 add rectangle to current image
// any other key clears rectangle drawing only
iKey=cvWaitKey(0);
switch(iKey)
{
case 27:
cvReleaseImage(&image);
cvDestroyWindow(window_name);
return 0;
case 32:
numOfRec++;
printf(" %d. rect x=%d\ty=%d\tx2h=%d\ty2=%d\n",numOfRec,roi_x0,roi_y0,roi_x1,roi_y1);
//printf(" %d. rect x=%d\ty=%d\twidth=%d\theight=%d\n",numOfRec,roi_x1,roi_y1,roi_x0-roi_x1,roi_y0-roi_y1);
// currently two draw directions possible:
// from top left to bottom right or vice versa
if(roi_x0<roi_x1 && roi_y0<roi_y1)
{
printf(" %d. rect x=%d\ty=%d\twidth=%d\theight=%d\n",numOfRec,roi_x0,roi_y0,roi_x1-roi_x0,roi_y1-roi_y0);
// append rectangle coord to previous line content
strPostfix+=" "+IntToString(roi_x0)+" "+IntToString(roi_y0)+" "+IntToString(roi_x1-roi_x0)+" "+IntToString(roi_y1-roi_y0);
}
else
//(roi_x0>roi_x1 && roi_y0>roi_y1)
{
printf(" hello line no 154\n");
printf(" %d. rect x=%d\ty=%d\twidth=%d\theight=%d\n",numOfRec,roi_x1,roi_y1,roi_x0-roi_x1,roi_y0-roi_y1);
// append rectangle coord to previous line content
strPostfix+=" "+IntToString(roi_x1)+" "+IntToString(roi_y1)+" "+IntToString(roi_x0-roi_x1)+" "+IntToString (roi_y0-roi_y1);
}
break;
}
}
while(iKey!=66);
{
// save to info file as later used for HaarTraining:
// <rel_path>\bmp_file.name numOfRec x0 y0 width0 height0 x1 y1 width1 height1...
if(numOfRec>0 && iKey==66)
{
//append line
/* TODO: Store output information. */
output << strPrefix << " "<< numOfRec << strPostfix <<"\n";
cvReleaseImage(&image);
}
else
{
fprintf(stderr, "Failed to load image, %s\n", strPrefix.c_str());
}
}
}}
output.close();
cvDestroyWindow(window_name);
closedir(dir_p);
return 0;
}
I ran the above code using Visual Studio 10.
When I run the above code it is opening the command window loading all the images (a new named window is also getting opened but getting but it is not staying for me to select the region) and then closing.
When I ran it using start without debugging option in VS10 it is I could see this:
Examining file img (6).jpeg
Loading image img (6).jpeg
Examining file img (6).JPG
Loading image img (6).JPG
Examining file img (7).jpeg
Loading image img (7).jpeg
Examining file img (7).jpg
Loading image img (7).jpg
Examining file img (8).jpeg
Loading image img (8).jpeg
Examining file img (8).jpg
Loading image img (8).jpg
Examining file img (9).jpeg
Loading image img (9).jpeg
Examining file img (9).jpg
Loading image img (9).jpg
Examining file img 1.jpeg
Loading image img 1.jpeg
the object marker fails and cannot load the image
I think that it is skipping the:
if((image=cvLoadImage(strPrefix.c_str(),1)) != 0){.....}
part of the code
There are few currently available object marking tools for Haar training. I use the tool in this link. Its perfectly worked for me. If you want to build your own tool please follow this tutorial. Any way I think when it comes to Haar training, it is waste of time to develop tools to capture coordinates because there are currently available tools for those and it is not the main goal of Haar training. Because Haar training takes more time to train and create cascade XML file. So its better to focus on training.