I am using mysql database for my face recognition project.Here I store images into the table and the images are stored as blob images.when select these images back, i need to write these blob images to separate image files using a file pointer and it will be stored into a folder in which the program resides.And for using those images, i need to read it again from that folder.Then only i can use that images to another function. But i need to use those blob images directly from the database(when we select it from the DB, i need to pass it to another function). So that i can reduce operations like reading it again from the folder.How can i convert bl .So for passing DB images directly to another function, i think we need to convert it's type or something.
void SelectImage()
{
MYSQL *conn;
MYSQL_RES *result;
MYSQL_ROW row;
char temp[900];
char filename[50];
unsigned long *lengths;
FILE *fp;
my_ulonglong numRows;
unsigned int numFields;
int mysqlStatus = 0;
MYSQL_RES *mysqlResult = NULL;
conn = mysql_init(NULL);
mysql_real_connect(conn, "localhost", "root", "athira#iot", "Athira", 0, NULL, 0);
int state=mysql_query(conn, "SELECT * FROM ima1");
mysqlResult=mysql_store_result(conn);
if(mysqlResult)
{
numRows=mysql_num_rows(mysqlResult);
}
cout<<"rows:"<<numRows<<endl;
for(int i=1;i<=numRows;i++){
sprintf(temp,"SELECT data FROM ima1 WHERE id=%d",i);
sprintf(filename,"Gen_Image%d.jpeg",i);
fp = fopen(filename, "wb");// open a file for writing.
cout<<temp<<" to "<<filename<<endl;
mysql_query(conn, temp);//select an image with id
result = mysql_store_result(conn);
row = mysql_fetch_row(result);//row contains row data
lengths = mysql_fetch_lengths(result);//this is the length of th image
fwrite(row[0], lengths[0], 1, fp);//writing image to a file
cout<<"selected..."<<endl;
img.create(100,100,CV_16UC1);
memcpy(img.data,row.data,lengths);
mysql_free_result(result);
fclose(fp);
}
mysql_close(conn);
}
I tried to convert it to Mat type but it's showing error..
error is this,
error: request for member ‘data’ in ‘row’, which is of non-class type ‘MYSQL_ROW {aka char**}’
If your images are stored using some image format (JPEG, PNG, BMP, ...) and not as raw pixel data, then you should be looking at the imdecode function in OpenCV.
If your data is stored as raw pixels, then you'd have to make sure that the memory layout of your BLOB data can be expressed using the step/stride functionality OpenCV uses to layout its matrices.
Related
I'm trying to convert a video file (.mp4) to a Dicom file.
I have succeeded to do it by storing single images (one per frame of the video) in the Dicom, but the result is a too large file, it's not good for me.
Instead I want to encapsulate the H.264 bitstream as it is stored in the video file, into the Dicom file.
I've tried to get the bytes of the file as follows:
std::ifstream inFile(file_name, std::ifstream::binary);
inFile.seekg(0, inFile.end);
std::streampos length = inFile.tellg();
inFile.seekg(0, inFile.beg);
std::vector<unsigned char> bytes(length);
inFile.read((char*)&bytes[0], length);
but I think I have missed something like encapsulating for the read bytes because the result Dicom file was a black image.
In python I would use pydicom.encaps.encapsulate function for this purpose:
https://pydicom.github.io/pydicom/dev/reference/generated/pydicom.encaps.encapsulate.html
with open(videofile, 'rb') as f:
dataset.PixelData = encapsulate([f.read()])
Is there anything in C ++ that is equivalent to the encapsulate function?
or any different way to get the encapsulated pixel data of video at one stream and not frame by frame?
This is the code of initializing the Dcmdataset, using the bytes extracted:
VideoFileStream* vfs = new VideoFileStream();
vfs->setFilename(file_name);
if (!vfs->open())
return false;
DcmDataset* dataset = new DcmDataset();
dataset->putAndInsertOFStringArray(DCM_SeriesInstanceUID, dcmGenerateUniqueIdentifier(new char[100], SITE_SERIES_UID_ROOT));
dataset->putAndInsertOFStringArray(DCM_SOPInstanceUID, dcmGenerateUniqueIdentifier(new char[100], SITE_INSTANCE_UID_ROOT));
dataset->putAndInsertOFStringArray(DCM_StudyInstanceUID, dcmGenerateUniqueIdentifier(new char[100], SITE_STUDY_UID_ROOT));
dataset->putAndInsertOFStringArray(DCM_MediaStorageSOPInstanceUID, dcmGenerateUniqueIdentifier(new char[100], SITE_UID_ROOT));
dataset->putAndInsertString(DCM_MediaStorageSOPClassUID, UID_VideoPhotographicImageStorage);
dataset->putAndInsertString(DCM_SOPClassUID, UID_VideoPhotographicImageStorage);
dataset->putAndInsertOFStringArray(DCM_TransferSyntaxUID, UID_MPEG4HighProfileLevel4_1TransferSyntax);
dataset->putAndInsertOFStringArray(DCM_PatientID, "987655");
dataset->putAndInsertOFStringArray(DCM_StudyDate, "20050509");
dataset->putAndInsertOFStringArray(DCM_Modality, "ES");
dataset->putAndInsertOFStringArray(DCM_PhotometricInterpretation, "YBR_PARTIAL_420");
dataset->putAndInsertUint16(DCM_SamplesPerPixel, 3);
dataset->putAndInsertUint16(DCM_BitsAllocated, 8);
dataset->putAndInsertUint16(DCM_BitsStored, 8);
dataset->putAndInsertUint16(DCM_HighBit, 7);
dataset->putAndInsertUint16(DCM_Rows, vfs->height());
dataset->putAndInsertUint16(DCM_Columns, vfs->width());
dataset->putAndInsertUint16(DCM_CineRate, vfs->framerate());
dataset->putAndInsertUint16(DCM_FrameTime, 1000.0 * 1 / vfs->framerate());
const Uint16* arr = new Uint16[]{ 0x18,0x00, 0x63, 0x10 };
dataset->putAndInsertUint16Array(DCM_FrameIncrementPointer, arr, 4);
dataset->putAndInsertString(DCM_NumberOfFrames, std::to_string(vfs->numFrames()).c_str());
dataset->putAndInsertOFStringArray(DCM_FrameOfReferenceUID, dcmGenerateUniqueIdentifier(new char[100], SITE_UID_ROOT));
dataset->putAndInsertUint16(DCM_PixelRepresentation, 0);
dataset->putAndInsertUint16(DCM_PlanarConfiguration, 0);
dataset->putAndInsertOFStringArray(DCM_ImageType, "ORIGINAL");
dataset->putAndInsertOFStringArray(DCM_LossyImageCompression, "01");
dataset->putAndInsertOFStringArray(DCM_LossyImageCompressionMethod, "ISO_14496_10");
dataset->putAndInsertUint16(DCM_LossyImageCompressionRatio, 30);
dataset->putAndInsertUint8Array(DCM_PixelData, (const Uint8 *)bytes.data(), length);
DJ_RPLossy repParam;
dataset->chooseRepresentation(EXS_MPEG4HighProfileLevel4_1, &repParam);
dataset->updateOriginalXfer();
DcmFileFormat fileformat(dataset);
OFCondition status = fileformat.saveFile("C://temp//videoTest", EXS_LittleEndianExplicit);
The trick is to redirect the value of the attribute PixelData to a file stream. With this, the video is loaded in chunks and on demand (i.e. when the attribute is accessed).
But you have to create the whole structure explicitly, that is:
The Pixel Data element
The Pixel Sequence with...
...the offset table
...a single item containing the contents of the MPEG file
Code
// set length to the size of the video file
DcmInputFileStream dcmFileStream(videofile.c_str(), 0);
DcmPixelSequence* pixelSequence = new DcmPixelSequence(DCM_PixelSequenceTag));
DcmPixelItem* offsetTable = new DcmPixelItem(DCM_PixelItemTag);
pixelSequence->insert(offsetTable);
DcmPixelItem* frame = new DcmPixelItem(DCM_PixelItemTag);
frame->createValueFromTempFile(dcmFileStream.newFactory(), OFstatic_cast(Uint32, length), EBO_LittleEndian);
pixelSequence->insert(frame);
DcmPixelData* pixelData = new DcmPixeldata(DCM_PixelData);
pixelData->putOriginalRepresentation(EXS_MPEG4HighProfileLevel4_1, nullptr, pixelSequence);
dataset->insert(pixelData, true);
DcmFileFormat fileformat(dataset);
OFCondition status = fileformat.saveFile("C://temp//videoTest");
Note that you "destroy" the compression if you save the file in VR Implicit Little Endian.
As mentioned above and obvious in the code, the whole MPEG file is wrapped into a single item in the PixelData. This is DICOM conformant but you may want to encapsulate single frames each in one item.
Note : No error handling presented here
I need to save an wxBitmap to SQLite to a blob type without save to disk or on some media.
i have mybitmap as wxBitmap;
First must convert to wxImage and get data.
Ok until now i hope, but how i can save the char data directly to blob db?
In sql must have
update mytable SET blob_column='??????' WHERE id='1'
or something like that. How must construct query?
wxImage img=mybitmap.ConvertToImage();
unsigned char* data=img.GetData();
int datalength=img.GetWidth()*img.GetHeight()*3;
char *myBuffer = (char *)data;
The code bellow is for wxSQLite3 ...
wxMemoryOutputStream mo;
img.SaveFile( mo, wxBITMAP_TYPE_PNG );
wxSQLite3Statement stmt = db.PrepareStatement("UPDATE mytable SET blob_column='?' WHERE id='1'");
stmt.Bind(0, (unsigned char *)mo.GetOutputStreamBuffer()->GetBufferStart(), mo.GetOutputStreamBuffer()->GetBufferSize());
stmt.ExecuteUpdate();
But how to translate for SQLite?
I want to use the DCMTK 3.6.1 library in an existing project that can create DICOM image. I want to use this library because I want to make the compression of the DICOM images. In a new solution (Visual Studio 2013/C++) Following the example in the DCMTK official documentation, I have this code, that works properly.
using namespace std;
int main()
{
DJEncoderRegistration::registerCodecs();
DcmFileFormat fileformat;
/**** MONO FILE ******/
if (fileformat.loadFile("Files/test.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 EXS_JPEGProcess14SV1
dataset->chooseRepresentation(EXS_JPEGProcess14SV1, ¶ms);
// 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);
metaInfo->putAndInsertString(DCM_ImplementationVersionName, "New Implementation Version Name");
//delete metaInfo->remove(DCM_ImplementationVersionName);
//dataset->remove(DCM_ImplementationVersionName);
// store in lossless JPEG format
fileformat.saveFile("Files/carrellata_esami_compresso.dcm", EXS_JPEGProcess14SV1);
}
}
DJEncoderRegistration::cleanup();
return 0;
}
Now I want to use the same code in an existing C++ application where
if (infoDicom.arrayImgDicom.GetSize() != 0) //Things of existing previous code
{
//I have added here the registration
DJEncoderRegistration::registerCodecs(); // register JPEG codecs
DcmFileFormat fileformat;
DcmDataset *dataset = fileformat.getDataset();
DJ_RPLossless params;
dataset->putAndInsertUint16(DCM_Rows, infoDicom.rows);
dataset->putAndInsertUint16(DCM_Columns, infoDicom.columns,);
dataset->putAndInsertUint16(DCM_BitsStored, infoDicom.m_bitstor);
dataset->putAndInsertUint16(DCM_HighBit, infoDicom.highbit);
dataset->putAndInsertUint16(DCM_PixelRepresentation, infoDicom.pixelrapresentation);
dataset->putAndInsertUint16(DCM_RescaleIntercept, infoDicom.rescaleintercept);
dataset->putAndInsertString(DCM_PhotometricInterpretation,"MONOCHROME2");
dataset->putAndInsertString(DCM_PixelSpacing, "0.086\\0.086");
dataset->putAndInsertString(DCM_ImagerPixelSpacing, "0.096\\0.096");
BYTE* pData = new BYTE[sizeBuffer];
LPBYTE pSorg;
for (int nf=0; nf<iNumberFrames; nf++)
{
//this contains all the PixelData and I put it into the dataset
pSorg = (BYTE*)infoDicom.arrayImgDicom.GetAt(nf);
dataset->putAndInsertUint8Array(DCM_PixelData, pSorg, sizeBuffer);
dataset->chooseRepresentation(EXS_JPEGProcess14SV1, ¶ms);
//and I put it in my data set
//but this IF return false so che canWriteXfer fails...
if (dataset->canWriteXfer(EXS_JPEGProcess14SV1))
{
dataset->remove(DCM_MediaStorageSOPClassUID);
dataset->remove(DCM_MediaStorageSOPInstanceUID);
}
//the saveFile fails too, and the error is "Pixel
//rappresentation non found" but I have set the Pixel rep with
//dataset->putAndInsertUint16(DCM_PixelRepresentation, infoDicom.pixelrapresentation);
OFCondition status = fileformat.saveFile("test1.dcm", EXS_JPEGProcess14SV1);
DJEncoderRegistration::cleanup();
if (status.bad())
{
int error = 0; //only for test
}
thefile.Write(pSorg, sizeBuffer); //previous code
}
Actually I made test with image that have on one frame, so the for cycle is done only one time. I don't understand why if I choose dataset->chooseRepresentation(EXS_LittleEndianImplicit, ¶ms); or dataset->chooseRepresentation(EXS_LittleEndianEXplicit, ¶ms); works perfectly but not when I choose dataset->chooseRepresentation(EXS_JPEGProcess14SV1, ¶ms);
If I use the same image in the first application, I can compress the image without problems...
EDIT: I think the main problem to solve is the status = dataset->chooseRepresentation(EXS_JPEGProcess14SV1, &rp_lossless) that return "Tag not found". How can I know wich tag is missed?
EDIT2: As suggest in the DCMTK forum I have added the tag about the Bits Allocated and now works for few images, but non for all. For some images I have again "Tag not found": how can I know wich one of tags is missing? As a rule it's better insert all the tags?
I solve the problem adding the tags DCM_BitsAllocated and DCM_PlanarConfiguration. This are the tags that are missed. I hope that is useful for someone.
At least you should call the function chooseRepresentation, after you have applied the data.
**dataset->putAndInsertUint8Array(DCM_PixelData, pSorg, sizeBuffer);**
dataset->chooseRepresentation(EXS_JPEGProcess14SV1, ¶ms);
I want to send an image over UDP network in small packets of size 1024 bytes.
i have two options.
imgBinaryFormatter->Serialize(memStream, objNewImage); // Sending an image object
OR
imgBinaryFormatter->Serialize(memStream, objNewImage->RawData); // Sending a raw data of image
what is difference in their content and when to use ?
For reference full function is given below
Image^ objNewImage = Image::FromFile(fullPath); // fullpath is full path of an image
MemoryStream^ memStream = gcnew MemoryStream();
Formatters::Binary::BinaryFormatter^ imgBinaryFormatter = gcnew Formatters::Binary::BinaryFormatter(); // Binary formatter
imgBinaryFormatter->Serialize(memStream, objNewImage); // Or objNewImage->RawData ??
arrImgArray = memStream->ToArray(); // COnvert stream to byte array
int iNoOfPackets = arrImgArray->Length / 1024;
int i;
for (i = 1; i < iNoOfPackets; i++){
socket->SendTo(arrImgArray, 1024*(i-1), 1024, SocketFlags::None, receiversAdd);
}
int remainedBytes = arrImgArray->Length - 1024 * iNoOfPackets;
socket->SendTo(arrImgArray, 1024 * iNoOfPackets, remainedBytes, SocketFlags::None, receiversAdd);
If you find improvements in code, feel free to edit code with suitable solution for memory constraint application.
It's better to use
the Image.Save Method (Stream, ImageFormat) for serialization into a Stream
and
the Image.FromStream Method (Stream) for deserialization from a Stream
or one of their overloads
I need specifically to load a JPG image that was saved as a blob. GDI+ makes it very easy to retrieve images from files but not from databases...
Take a look at Image::Image(IStream *, BOOL). This takes a pointer to a COM object implementing the IStream interface. You can get one of these by allocating some global memory with GlobalAlloc and then calling CreateStreamOnHGlobal on the returned handle. It'll look something like this:
shared_ptr<Image> CreateImage(BYTE *blob, size_t blobSize)
{
HGLOBAL hMem = ::GlobalAlloc(GMEM_MOVEABLE,blobSize);
BYTE *pImage = (BYTE*)::GlobalLock(hMem);
for (size_t iBlob = 0; iBlob < blobSize; ++iBlob)
pImage[iBlob] = blob[iBlob];
::GlobalUnlock(hMem);
CComPtr<IStream> spStream;
HRESULT hr = ::CreateStreamOnHGlobal(hMem,TRUE,&spStream);
shared_ptr<Image> image = new Image(spStream);
return image;
}
But with error checking and such (omitted here to make things clearer)
First fetch your blog into a byte array then use something like this:
public static Image CreateImage(byte[] pict)
{
System.Drawing.Image img = null;
using (System.IO.MemoryStream stream = new System.IO.MemoryStream(pict)) {
img = System.Drawing.Image.FromStream(stream);
}
return img;
}