Save a single image#
Here comes the basic example of writing an image to your hard-disk. As an example, we generate a single-channel gray-ramp image of size 512x512 named ImageGrayRamp
and write it to disk using the PNG format:
* Save a single image to C:\TEMP in format PNG gen_image_gray_ramp (ImageGrayRamp, 1, 1, 128, 256, 256, 512, 512) write_image (ImageGrayRamp, 'png', 0,'C:/TEMP/testimage.png')
File format#
The file format is specified in the parameter Format
of the operator write_image
. Normally, we recommend saving images in a lossless image format. Ideally, the file format should be able to save all of HALCON's image data. The file format should be readable for 3rd-party applications for quick overviews e.g. in Windows Explorer. Saving should be reasonable fast while compressing (without information loss!) as good as possible. Therefore we recommend saving images in PNG format, i.e. with Format
set to 'png'
. PNG can save 1-channel images and 3-channel images (color images) and can also save the image domain (ROI) as alpha channel. TIFF would be possible, too, but the format seems a bit uncommon nowadays and BMP is uncompressed and seems a bit Windows specific.
On the other hand, lossy image formats like JPG can save a lot of disk space, but at the cost of introducing artifacts into the image. In the following example you can see artifacts which were added when saving the image of a circle with the write_image option jpeg 20
:
The image formats hobj
and ima
are HALCON-specific. The file format hobj
is best to save images with all information available but it is not recognized by any 3rd-party application and therefore is a bit cumbersome to manage e.g. with Windows Explorer. I'd recommend using hobj
if you have special images with more than three channels or with an image type other than byte
(e.g. uint2
). ima
is the legacy format of HALCON to save images. It generates two files, one with the extension .ima
and one with the extension .exp
which contains additional metadata (for example, size and format of the image).
To select the right image file format for archiving images is very important. The following table tries to help in choosing the right format. The table rows are sorted with the (in our opinion) best image file formats for machine vision coming first, but this of course depends on your specific needs:
Format | Lossless | channels | domain | types | multiple objects | generally recognized1 |
---|---|---|---|---|---|---|
'png' | ✅ | 1, 3 | ✅ | byte , uint2 | ❌ | ✅ |
'tiff' | ✅ | any | ✅ | byte ,uint2 ,real ,… | ✅ | ✅ |
'hobj' | ✅ | any | ✅ | any | ✅ | ❌ |
'bmp' | ✅ | 1, 3 | ❌ | byte | ❌ | ✅ |
'jpeg' | ❌ | 1, 3 | ❌ | byte | ❌ | ✅ |
'jp2' (JPG-2000) | ✅, ❌ | any | ✅ | byte , uint2 | ❌ | ❌ |
'jpegxr' 2 | ✅, ❌ | any | ✅ | byte ,uint2 ,real ,… | ✅3 | ❌ |
'ima' | ✅ | 1 | ❌ | any4 | ❌ | ❌ |
- file format can be assumed to be readable by third-party image processing applications
- file extension for JPEG-XR is
.jxr
- saves in separate files and requires multiple file names in
FileName
- except
complex
andvector_field
Other parameters of write_image#
The parameter FillColor
can be left at the default value of 0. In almost 10 years of using HALCON I never had to change this default of operator write_image
.
The parameter FileName
can contain the file name only to save the image in the current directory. If no extension is given, the extension corresponding to the Format
is automatically added to the file name. If an absolute path is specified, you have to use forward slashes, even on Windows. A few examples are:
* Save PNG in current directory. The following two lines * produce the same output file testimage.png write_image (ImageGrayRamp, 'png', 0,'testimage.png') write_image (ImageGrayRamp, 'png', 0,'testimage') * Save image file 'testimage.tif' in TIFF format in directory C:\TEMP write_image (ImageGrayRamp, 'tiff', 0,'C:/TEMP/testimage') * PNG file format can also save the domain of a HALCON image: gen_circle (Circle, 200, 200, 100.5) reduce_domain (ImageGrayRamp, Circle, ImageReduced) write_image (ImageReduced, 'png', 0, 'C:/TEMP/image_reduced.png')
Save multiple images#
If you want to save multiple images, e.g. acquired from an acquisition device, you have to implement some code to give the image files names with continuous numbers:
* Example code to acquire images from the first DirectShow device (a Webcam?) AcqName := 'DirectShow' info_framegrabber(AcqName,'device',__,Devices) gen_empty_obj (ImagesCaptured) for Index := 0 to 29 by 1 grab_image (Image, AcqHandle) * append current Image to ImagesCaptured concat_obj (ImagesCaptured, Image, ImagesCaptured) endfor * Example code to write multiple images stored in ImagesCaptured * to separate files 'image000', 'image001', ... TargetDir := 'C:/TEMP' count_obj (ImagesCaptured, NumberImages) for Index0 := 0 to NumberImages-1 by 1 select_obj (ImagesCaptured, CurrentImage, Index0+1) * The $'.3' makes sure that the numbers always consist of 3 digits. * Leading zeros are prepended as needed. This leads to better sorting of the * files: * good: sorted 'image000', 'image002', 'image003', 'image004', ... * bad: sorted 'image0', 'image1', 'image10', 'image2', 'image3', ... write_image (CurrentImage, 'png', 0, TargetDir + '/image_' + Index0$'.3') endfor
As of HALCON 13.0 (update: still the case in HALCON 25.05), the operator write_image
is not parallelized, which means that it can take a very long time if you want to write many images. The following snippet parallelizes write_image
manually. On my CPU (4 cores, 8 threads) and a SSD drive as write target this reduces the time needed to write 30 color images of size 1920x1080 from 35 seconds (sequential) to 6 seconds (parallel):
if (|FileNames| <= 1) write_image (Images, Format, FillColor, FileNames) return () endif get_system ('processor_num', NumThreads) * if a large number is returned in NumThreads we get in HDevelop (tested with 24.11): * Unhandled program exception: * Thread creation failed: exceeded maximum number of subthreads (HDevelop error code: 21052) * while calling 'write_image' in procedure 'WriteImageParallel' line: 16. * Exceeded the maximum number of subthreads: Actual: 20. Max: 20 * This parameter can be changed via the Preferences Dialog / General Options / General Options count_obj (Images, NumImages) VecThreadID := {} for IndexImage0 := 0 to NumImages-1 by 1 if (IndexImage0 % NumThreads == 0) convert_vector_to_tuple (VecThreadID, ThreadID) par_join (ThreadID) VecThreadID := {} ThreadID := [] endif select_obj (Images, ThisImage, IndexImage0 + 1) par_start<VecThreadID.at(IndexImage0%NumThreads)> : write_image (ThisImage, Format, 0, FileNames[IndexImage0]) endfor convert_vector_to_tuple (VecThreadID, ThreadID) par_join (ThreadID) return ()
Other possibilities#
write_object#
Instead of using write_image
with Format
'hobj'
the operator write_object
can be used:
write_object (Images, TargetDir + '/myobjects')
The extension hobj
is automatically added to the filename. Use this for example if you want to access the saved images with HALCON only.
Serialize / deserialize#
Images can also be saved to disk in HALCON's serialized data stream format. This can be useful if additional data should be saved in the same file, e.g. a shape model, which could also be serialized and appended to the stream data file:
* Save images to disk in HALCON's serialized data stream format open_file (TargetDir + '/myserialized.dat', 'output_binary', FileHandle) * serialize_image (Images, SerializedItemHandle) serialize_object (Images, SerializedItemHandle) fwrite_serialized_item (FileHandle,SerializedItemHandle) close_file (FileHandle) * Read images from disk in HALCON's serialized data stream format open_file (TargetDir + '/myserialized.dat', 'input_binary', FileHandle) fread_serialized_item (FileHandle, SerializedItemHandle) * deserialize_image (ImagesRead, SerializedItemHandle) deserialize_object (ImagesRead, SerializedItemHandle) close_file (FileHandle)
Summary#
Although the task to write images to disk and archive them for later usage sounds like a simple job at first, it can be a surprisingly complex topic. We hope to have clarified the various possibilities a bit. Please contact us if you have any questions or need help with your project.