Compress DICOM file with DCMTK (C++) - c++

damn i'm very frustated...
Following the example in this page http://support.dcmtk.org/docs/mod_dcmjpeg.html, I have written a C++ program to decompress a JPEG-compressed DICOM image file
Now I want to do the vice versa, from uncompressed to compressed and if I use the other example in the same page, with the same (or other file) the code compile and run but is not able to compress the file...
I saw that afetr the following code, the originale Xfer and the Current is the same, and this is not good because need to be different
dataset->chooseRepresentation(EXS_JPEGProcess14SV1, &params);
It's like the chooseRepresentation method fail....
More the line
dataset->canWriteXfer(EXS_JPEGProcess14SV1)
return false
I saw that in the dcpixel.cc file, with debugging the code go in
DcmPixelData::canChooseRepresentation(.........
....
....
// representation not found, check if we have a codec that can create the
// desired representation.
if (original == repListEnd)
{
result = DcmCodecList::canChangeCoding(EXS_LittleEndianExplicit, toType.getXfer());
}
and result is FALSE....
How can I fix it? Someone have a code that works to compress a DICOM image with DCMTK or another library
This is the full code:
int main()
{
//dcxfer.h
DJDecoderRegistration::registerCodecs(); // register JPEG codecs
DcmFileFormat fileformat;
/**** MONO FILE ******/
if (fileformat.loadFile("Files/cnv3DSlice (1)_cnv.dcm").good())
{
DcmDataset *dataset = fileformat.getDataset();
DcmItem *metaInfo = fileformat.getMetaInfo();
DJ_RPLossless params; // codec parameters, we use the defaults
// this causes the lossless JPEG version of the dataset to be created
dataset->chooseRepresentation(EXS_JPEGProcess14SV1, &params);
// check if everything went well
if (dataset->canWriteXfer(EXS_JPEGProcess14SV1))
{
// force the meta-header UIDs to be re-generated when storing the file
// since the UIDs in the data set may have changed
delete metaInfo->remove(DCM_MediaStorageSOPClassUID);
delete metaInfo->remove(DCM_MediaStorageSOPInstanceUID);
// store in lossless JPEG format
fileformat.saveFile("Files/test_jpeg_compresso.dcm", EXS_JPEGProcess14SV1);
}
}
DJDecoderRegistration::cleanup(); // deregister JPEG codecs
return 0;
}

When trying to compress an image you need to call
DJEncoderRegistration::registerCodecs();
Decompress is
DJDecoderRegistration::registerCodecs();

Related

Tesseract/Leptonica proper way to handle single and multipage images?

I got a few questions about how input images are handled in Tesseract (with leptonica).
What I'm trying to do here is to have a method that can process any image file (no specific format requiered) and feed it later to the tesseract API, but this doesn't seems to be the right way of doing things with leptonica...
Here is an exemple of what I'm doing:
string tmpFile ="path/to/my/file";
// Trying to load a PIXA struct, since it can handle multipage images
PIXA* sourceImg =pixaRead(tmpFile.c_str());
if (sourceImg == NULL) {
// this happen when pixaRead method fails to load the image
// So we suppose it's a single page image-file.
sourceImg =new PIXA;
sourceImg->n =1;
sourceImg->pix =(Pix**)malloc(sizeof(Pix*));
assert(sourceImg->pix != NULL);
sourceImg->pix[0] =pixRead(tmpFile.c_str());
sourceImg->refcount =1;
}
api = new tesseract::TessBaseAPI();
if (api->Init(NULL, "eng")) {
fprintf(stderr, "Could not initialize tesseract.\n");
exit(1);
}
// Now we can process each pages
for(int i=0; i<sourceImg->n; i++) {
// results is an object I use to save text from each documents,
// with page count
if (i > 0)
results.addPage();
Pix* image =sourceImg->pix[i];
api->SetImage(image);
// Get OCR result
outText = api->GetUTF8Text();
// Here I process stuff, not really important
int dummyPos=0;
results.addLine(outText, dummyPos, dummyPos, dummyPos, dummyPos);
delete [] outText;
}
pixaDestroy(&sourceImg);
api->End();
So this is working, but not in the way I want, because even if I use a multipage tiff I got the following message when loading the image:
Error in pixaReadStream: not a pixa file
Error in pixaRead: pixa not read
It's still able to process the document thank's to the "pixRead" method I use in case the "pixaRead" fails...
Can someone explain to me what is wrong with my use of the "pixaRead" function?
And is it possible to handle single and multipage images with something like that?
PS: I'm using Tesseract V4.0 and Leptonica V1.74.4
Thanks in advance!
Use pixaReadMultipageTiff to read TIFF image (single or multiple pages) and pixRead for other image formats.

Write exif data to jpeg stream

I try to insert some EXIF Data in a JPEG stream. I am using libexif for that.
The libexif example shows how to open a file -> add the data -> and then save the file. What I have is a pointer (void * JPEGPointer) to a JPEG stream. So I want to just add the from libexif generated data to this pointer for sending it via FTP. Not saving to a file. The following code is basically the example from libexif with some not working memcpy() attempts from myself. The JPG File is corrupted after the memcpy so i can not open it with any Software. I think i am copying the exif to the wrong position. I can not use any aditional library unfortunately.
// Set the image options
exif_data_set_option(exif, EXIF_DATA_OPTION_FOLLOW_SPECIFICATION);
exif_data_set_data_type(exif, EXIF_DATA_TYPE_COMPRESSED);
exif_data_set_byte_order(exif, FILE_BYTE_ORDER);
// Create the mandatory EXIF fields with default data
exif_data_fix(exif);
/* Create a EXIF_TAG_USER_COMMENT tag. This one must be handled
* differently because that tag isn't automatically created and
* allocated by exif_data_fix(), nor can it be created using
* exif_entry_initialize() so it must be explicitly allocated here.
*/
entry = createTag(exif, EXIF_IFD_EXIF, EXIF_TAG_USER_COMMENT,
sizeof(ASCII_COMMENT) + sizeof(FILE_COMMENT) - 2);
/* Write the special header needed for a comment tag */
memcpy(entry->data, ASCII_COMMENT, sizeof(ASCII_COMMENT)-1);
/* Write the actual comment text, without the trailing NUL character */
memcpy(entry->data+8, FILE_COMMENT, sizeof(FILE_COMMENT)-1);
/* createTag() happens to set the format and components correctly for
* EXIF_TAG_USER_COMMENT, so there is nothing more to do. */
/* Get a pointer to the EXIF data block we just created */
exif_data_save_data(exif, &exif_data, &exif_data_len);
assert(exif_data != NULL);
//copy exif data to my JPEGPointer...not working like that
memcpy(JPEGPointer+ exif_data_len * sizeof(uint8_t), JPEGPointer, sizeof(JPEGPointer)+exif_data_len);
free(exif_data);
exif_data_unref(exif);
Any ideas how to put that EXIF data to the correct position in the JPEG data?

How to convert/create a dicom image from jpeg using Imebra library?

I want to create of convert a jpeg image to a dicom image using imebra library on iOS platform. In the objective c examples of the library the steps to convert or read a dicom into jpeg are given, however, I am going through the documentation and trying to achieve vice versa (i.e. jpeg to dicom). I have no background of c++ so any help would be appreciated. Links to the library and documentation:
1.https://imebra.com
2.https://imebra.com/wp-content/uploads/documentation/imebra_build_2013-10-30_10-00-11/html/dicom2jpeg_2dicom2jpeg_8cpp-example.html
Some basic code below, thanks in advance.
-(void)createDcmFromJpg
{
NSString *imagePath = [[NSBundle mainBundle]pathForResource:#"test2" ofType:#"jpeg"];
//Create read stream
using namespace puntoexe;
ptr<stream> readStream(new stream);
readStream->openFile(NSStringToStringW(imagePath), std::ios::in);
//create dataset
ptr<streamReader> reader(new streamReader(readStream));
ptr<imebra::dataSet> testDataSet = imebra::codecs::codecFactory::getCodecFactory()->load(reader);
//set Tags
testDataSet->setString(0x0010, 0, 0x0010, 0, "testStr");
testDataSet->setString(0x0010, 0, 0x0010, 1, "testStr1");
//Next step/steps ?
}
The imebra::dataSet represents a collection of Dicom tags.
When you read a file (jpeg or dicom), then Imebra creates a dataSet which is a set of Dicom tags.
When reading a Dicom file then the dataSet will mirror exactly the tags stored in the Dicom file, while when reading a jpeg image Imebra will create a dataSet containing the proper dicom tag that embeds the jpeg image: all the needed Dicom tags will be already in the dataSet and you can add your own (like patient name, etc).
The next step consists in saving the dataSet to a Dicom stream:
with Imebra V4 (current):
// Load jpeg
std::unique_ptr<imebra::Dataset> testDataset(imebra::CodecFactory::load("/path/to/jpegfile.jpg"));
// Save as Dicom
imebra::CodecFactory::save(testDataset, "/path/to/file.dcm", imebra::codecType_t::dicom);
with Imebra 2015 (legacy):
// Open the Dicom file for writing
ptr<stream> writeStream(new stream);
writeStream->openFile(NSStringToStringW(dicomfilepath), std::ios::out);
// Declare the writer (will take care of writing into the stream)
ptr<streamWriter> writer (new streamWriter(writeStream));
// Use the dicom codec to write the dataSet into the file
ptr<imebra::codecs::codec> dicomCodec(new imebra::codecs::dicomCodec);
dicomCodec->write(writer, testDataSet);

Trying to encode a GIF file using giflib

I am given image data and color table I am trying to export it as a single frame GIF using giflib. I looked into the API, but can't get it to work. The program crashes even at the first function:
GifFileType image_out;
int errorCode = 0;
char* fileName = "SomeName.gif";
image_out = *EGifOpenFileName(fileName,true, &errorCode);
It is my understanding that I first need to open a file by specifying it's name and then update it with fileHandle. Then Fill in the screen description, the extension block the image data and add the 3B ending to the file. Then use EGifSpew to export the whole gif. The problem is that I can't even use EGifOpenFileName(); The program crashes at that line.
Can someone help me the API of giflib? This problem is getting really frustrating.
Thanks.
EDIT:
For the purposes of simple encoding I do not want to specify a color table and I just want to encode a single frame GIF.
The prototype is:
GifFileType *EGifOpenFileName(char *GifFileName, bool GifTestExistance, int *ErrorCode)
You should write as
GifFileType* image_out = EGifOpenFileName(fileName,true, &errorCode);
Note GifFileType is not POD type so you should NOT copy like that.

How do I load an image (raw bytes) with OpenCV?

I am using Mat input = imread(filename); to read an image but I'd like to do it from memory instead. The source of the file is from an HTTP server. To make it faster, instead of writing the file to disk and then use imread() to read from it, i'd like to skip a step and directly load it from memory. How do I go about doing this?
Updated to add error
I tried the following but I'm getting segmentation fault
char * do_stuff(char img[])
{
vector<char> vec(img, img + strlen(img));
Mat input = imdecode(Mat(vec), 1);
}
See the man page for imdecode().
http://docs.opencv.org/modules/highgui/doc/reading_and_writing_images_and_video.html#imdecode
I had a similar problem. I needed to decode a jpeg image stream in memory and use the Mat image output for further analysis.
The documentation on OpenCV::imdecode did not provide me enough information to solve the problem.
However, the code here by OP worked for me. This is how I used it ( in C++ ):
//Here pImageData is [unsigned char *] that points to a jpeg compressed image buffer;
// ImageDataSize is the size of compressed content in buffer;
// The image here is grayscale;
cv::vector<unsigned char> ImVec(pImageData, pImageData + ImageDataSize);
cv:Mat ImMat;
ImMat = imdecode(ImVec, 1);
To check I saved the ImMat and was able to open the image file using a image viewer.
cv::imwrite("opencvDecodedImage.jpg", ImMat);
I used : OpenCV 2.4.10 binaries for VC10 on x86.
I hope this information can help others.