BI DAT Tool - Filter/inspect/delete Blue Iris AI-analysis 'DAT' files; Extract JPG images and JSON results

I'll tackle the easier-to-answer questions first... and respond to your comment/questions regarding the super confusing "IfAi" arguments in a separate post later when I have more time.

Ok, I was just trying to filter/process a cancelled alert by adding an explanation point to the alert memo (i.e. "nothing found!") (when the AI misses something entirely) and it wasn't processed. I think because the tool ignores (or can't read) the database alert memos of cancelled alerts? (Or I'm just missing something.) If possible, could you add that feature?
The script reads the memo of every alert in the database.
Did you try something like this? It works for me.
bi_dat_tool.ps1 -AlMemoTags "nothing" -NoInspect
Remember that the argument -AlMemoTags searches for ANY substring in the Alert's database memo value.
(I often use argument -NoInspect to return results faster because the script does not look inside the DAT file.)

I didn't understand the -Patterns "FE.","FD.","GT" argument. I think they are your camera names lol?
Argument -Patterns searches for ANY substring the DAT file name, and returns/performs operations on only those DAT files.

Yes, "FE.", etc. are some of my camera names. Additionally, I often use the -Patterns argument to process a single DAT file. For example, to process only this DAT file "FE.20230922_180000.1515866.17-0.dat", I would try using -Patterns "1515866", instead of the harder to type -Files "FE.20230922_180000.1515866.17-0"

Argument -Patterns "FE.","FD.","GT", returns/processes DAT files for only for a ad-hoc group of 3 of my cameras.

Suggestion for 1.2: Can you make -SingleFolder an argument that obeys the user set destination path, rather than a folder named SingleFolder? Basically I'd like to extract directly into the destination Images folder. I thought about updating it in the script, but then I would have to remember to change it with every update lol
I'm a little confused. Argument -SingleFolder already creates a subfolder named 'SingleFolder" in the script's destination folder (user setting $dest_path).
You can easily use Windows Explorer to move or rename this folder. I often rename it to something like 'SingleFolder1", "singleFolder2" so I can gather different sets of images.
The reason I use a subfolder instead of dumping the images directly to the script's destination folder is because it makes it easier to manage image collections.
 
Last edited:
  • Like
Reactions: EvanVanVan
The script reads the memo of every alert in the database.
Did you try something like this? It works for me.
bi_dat_tool.ps1 -AlMemoTags "nothing" -NoInspect
Remember that the argument -AlMemoTags searches for ANY substring in the Alert's database memo value.
(I often use argument -NoInspect to return results faster because the script does not look inside the DAT file.)
Yeah, something must be screwy because that command does not work for me. It returns No DAT files found via the requested filters (which is not accurate).

This DAT file specifically is a cancelled alert with "nothing found" in the alert memo. As you can see, I can't get the tool to read the alert memo (It's the same result without -NoInspect). It's the same every cancelled alert.
1695641018740.png

1695641039870.png



I'm a little confused. Argument -SingleFolder already creates a subfolder named 'SingleFolder" in the script's destination folder (user setting $dest_path).
You can easily use Windows Explorer to move or rename this folder. I often rename it to something like 'SingleFolder1", "singleFolder2" so I can gather different sets of images.
The reason I use a subfolder instead of dumping the images directly to the script's destination folder is because it makes it easier to manage image collections.

I move the pictures elsewhere right away, so for me going into the another subfolder is an extra couple clicks but no big deal. Thank you
 
This DAT file specifically is a cancelled alert with "nothing found" in the alert memo. As you can see, I can't get the tool to read the alert memo (It's the same result without -NoInspect). It's the same every cancelled alert.
1695641018740.png

1695641039870.png
I'm not at my machine to test this. Can you try again without -NoInspect... I cannot remember now if v1.1 always imports the database alertlist, regardless of argument - NoInspect.
 
Last edited:
And without -NoInspect? (I edited my previous reply after you read it - sorry).
Same result without -NoInspect.

1695681008128.png


Again, the Alert Memo is Blue Iris is "nothing found" as shown in the earlier screenshot. FWIW, I have "spider" in the "AI: To cancel" field (although it never reached the 70% min-confidence to actually identify one). I don't confirm or cancel vehicles...(But that hit a 95% confidence in this alert.)

1695681674732.png


edit: For additional troubleshooting, here's a cancelled alert where a spider was identified (and cancelled).

1695681852767.png


1695681929006.png


edit2: Here's the userprofile for the dat tool. Incase something's maybe not enabled properly?
1695682123749.png
 
Last edited:
Script updated to V1.2. see post #1.

Changelog:
  1. NEW: added new 'RO' column to output to show if the DAT (and associated Alert JPG) files have their read-only attributes set
  2. NEW: added new 'JpgExifMemo' column to output; to show if the JPG's Exif metadata contains the same memo as the Alert's db entry
  3. NEW: argument -ReadOnly sets the read-only attribute for found DAT files (and associated Alert JPG files, if present)
  4. NEW: argument -FixJpgMetadata forces found DAT files Alert JPGs Exif metadata to match the Alert's database memo
  5. CHANGE: argument -Delete now ALWAYS performs a database Repair/Regenerate (as required, per Blue Iris support)
  6. NEW: argument -Delete now automatically backs up the Blue Iris database folder to the '\_backup*' subfolder (the purpose is to facilitate recovery of the Blue Iris database, if ever needed)
  7. NEW: added function BIHttpCall() to support database Repair/Regenerate actions
  8. NEW: added new user-setting to optionally use BI user credentials with Blue Iris HTTP interface commands
  9. NEW: added new user-setting to optionally open the output CSV file in the default Windows application
  10. NEW: added descriptive/explanatory '_README.txt' files to all programmatically created folders
  11. IMPROVEMENT: warning now issued when a Blue Iris JSON interface command requires an administrative account
  12. IMPROVEMENT: warning now issued when attempting to post to the Blue Iris logfile when using a non-administrative account
  13. CHANGE: reworked handling of failed JSON interface calls in function BiJsonCall()
  14. CHANGE: reworked posting to the Blue Iris logfile; eliminated function PostCustomBiLogEntry()

The following screenshot shows the new columns in the CSV file output.
output_example_v1.2.png

This screenshot shows the currently available set of commandline parameters.
bi_dat_tool_help.v1.2.png
 
Last edited:
Yeah, something must be screwy because that command does not work for me. It returns No DAT files found via the requested filters (which is not accurate).

This DAT file specifically is a cancelled alert with "nothing found" in the alert memo. As you can see, I can't get the tool to read the alert memo (It's the same result without -NoInspect). It's the same every cancelled alert.
1695641018740.png

1695641039870.png
First, I apologize for the delay in responding to your post. Family matters took over my life the past 2+ weeks.

I've yet to be able to reproduce what you are seeing. I'm starting to wonder if you may have 2 or more DAT files with similar basenames. If so, this would create an an issue when the script creates a lookup table from the output of the JSON alertlist command.

The easiest way to test this theory would be the copy the basename of DAT file name in question from the output, and search for it in the Blue Airs Alerts folder, as shown below. (In this example, the alert has one DAT file, and one JPG file.)

1696780325578.png


ANOTHER scenario might be that DAT file is 'orphaned' - that is, it does not have an actual paired alertlist entry in the database… From the screenshot, I know you think you've identified the associated database entry, but to be sure we would need to examine the JSON clipstats response for the database record... EDIT: I've DM'd you a script to inspect the clipstats for any alert in the Blue Iris clips list.

Of course, a Database/Regenerate action should fix any ‘orphaned’ DAT files.
 
Last edited:
  • Like
Reactions: EvanVanVan
@jaydeel First, thank you for creating this script.

Using v1.2, I want to export images and json for voxel51.com for training.
I assume I can ignore the warnings at the beginning (why invalid session, I specified "admin" password in config) but the errors when it's inspecting EXIF is concerning. Any ideas?

Code:
PS C:\bin> bi_dat_tool.ps1 -AgeHours 154 -SaveJPGs -SaveJSON -SingleFolder                          
Found 3 DAT files matching Age >=154 hrs                                                            
WARNING: JsonCmd 'alertlist' failed with reason 'Invalid session'                                   
WARNING: JsonCmd 'alertlist' failed with reason 'Invalid session'                                   
WARNING: JsonCmd 'alertlist' failed with reason 'Invalid session'                                   
WARNING: JsonCmd 'logout' failed with reason 'Invalid session' 
                                                                                                                                         
Inspecting 1/3 - SidewalkRight.20240315_050000.1133879.3-3.dat ...                                  
AI: Models used by DAT: ipcam-combined                                                              
AI: Labels found in DAT's imgs: person(1,2,3,4,5,6)                                                 
Saved 6 jpg + 6 json files                                                                                                                                                                                  

Inspecting 2/3 - SidewalkLeft.20240315_050000.1132087.5-0.dat ...                                   
AI: Models used by DAT: objects                                                                     
AI: Labels found in DAT's imgs: person(1,2,3,4,5,6)                                                 
Saved 6 jpg + 6 json files                                                                                                                                                                                  

Inspecting 3/3 - OverviewPTZ.20240315_050000.1163169.5-0.dat ...                                    
AI: Models used by DAT: objects                                                                     
AI: Labels found in DAT's imgs: person(1,2,3,4,5,6)                                                 
Saved 6 jpg + 6 json files                                                                                                                                                                                  

Inspecting Exif metadata in associated Alert JPG files...                                           
Found 3 Alert JPG files with unexpected metadata (not matching database alert memo)                 

You cannot call a method on a null-valued expression.                                                
At C:\bin\BI_dat_tool.ps1:4605 char:3                                                                
+         $val = $item.toString()                                                                    
+         ~~~~~~~~~~~~~~~~~~~~~~~                                                                        
+ CategoryInfo          : InvalidOperation: (:) [], RuntimeException                                 
+ FullyQualifiedErrorId : InvokeMethodOnNull                                                                                                                                                                You cannot call a method on a null-valued expression.                                                   At C:\bin\BI_dat_tool.ps1:4606 char:3                                                                
+         $attribs[$i] = $val.padLeft($max_len," ")                                                  
+         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~                                                      
+ CategoryInfo          : InvalidOperation: (:) [], RuntimeException                                 
+ FullyQualifiedErrorId : InvokeMethodOnNull                                                                                                                                                                You cannot call a method on a null-valued expression.                                                   At C:\bin\BI_dat_tool.ps1:4605 char:3
+         $val = $item.toString()
+         ~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull

You cannot call a method on a null-valued expression.
At C:\bin\BI_dat_tool.ps1:4606 char:3
+         $attribs[$i] = $val.padLeft($max_len," ")
+         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull

You cannot call a method on a null-valued expression.
At C:\bin\BI_dat_tool.ps1:4605 char:3
+         $val = $item.toString()
+         ~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull

You cannot call a method on a null-valued expression.
At C:\bin\BI_dat_tool.ps1:4606 char:3
+         $attribs[$i] = $val.padLeft($max_len," ")
+         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull


Processed 3 DAT file(s)

Saved 18/18 available JPG file(s)

(Note: the following table is available as 'C:\BI_dat_tool\_output\output.csv')

File                                          Flags RO AgeHrs ImgsCnt ModelsUsed     LabelsFound AlertM
                                                                                                 emo
----                                          ----- -- ------ ------- ----------     ----------- ------
SidewalkRight.20240315_050000.1133879.3-3.dat    --       154       6 ipcam-combined person
SidewalkLeft.20240315_050000.1132087.5-0.dat     --       154       6 objects        person
OverviewPTZ.20240315_050000.1163169.5-0.dat      --       154       6 objects        person


PS C:\bin>
 
Last edited:
@jaydeel First, thank you for creating this script.

Using v1.2, I want to export images and json for voxel51.com for training.
I assume I can ignore the warnings at the beginning (why invalid session, I specified "admin" password in config) but the errors when it's inspecting EXIF is concerning. Any ideas?

Code:
PS C:\bin> bi_dat_tool.ps1 -AgeHours 154 -SaveJPGs -SaveJSON -SingleFolder                    
Found 3 DAT files matching Age >=154 hrs                                                      
WARNING: JsonCmd 'alertlist' failed with reason 'Invalid session'                             
WARNING: JsonCmd 'alertlist' failed with reason 'Invalid session'                             
WARNING: JsonCmd 'alertlist' failed with reason 'Invalid session'                             
WARNING: JsonCmd 'logout' failed with reason 'Invalid session'
                                                                                                                                   
Inspecting 1/3 - SidewalkRight.20240315_050000.1133879.3-3.dat ...                            
AI: Models used by DAT: ipcam-combined                                                        
AI: Labels found in DAT's imgs: person(1,2,3,4,5,6)                                           
Saved 6 jpg + 6 json files                                                                                                                                                                            

Inspecting 2/3 - SidewalkLeft.20240315_050000.1132087.5-0.dat ...                             
AI: Models used by DAT: objects                                                               
AI: Labels found in DAT's imgs: person(1,2,3,4,5,6)                                           
Saved 6 jpg + 6 json files                                                                                                                                                                            

Inspecting 3/3 - OverviewPTZ.20240315_050000.1163169.5-0.dat ...                              
AI: Models used by DAT: objects                                                               
AI: Labels found in DAT's imgs: person(1,2,3,4,5,6)                                           
Saved 6 jpg + 6 json files                                                                                                                                                                            

Inspecting Exif metadata in associated Alert JPG files...                                     
Found 3 Alert JPG files with unexpected metadata (not matching database alert memo)           

You cannot call a method on a null-valued expression.                                          
At C:\bin\BI_dat_tool.ps1:4605 char:3                                                          
+         $val = $item.toString()                                                              
+         ~~~~~~~~~~~~~~~~~~~~~~~                                                                  
+ CategoryInfo          : InvalidOperation: (:) [], RuntimeException                           
+ FullyQualifiedErrorId : InvokeMethodOnNull                                                                                                                                                                You cannot call a method on a null-valued expression.                                                   At C:\bin\BI_dat_tool.ps1:4606 char:3                                                          
+         $attribs[$i] = $val.padLeft($max_len," ")                                            
+         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~                                                
+ CategoryInfo          : InvalidOperation: (:) [], RuntimeException                           
+ FullyQualifiedErrorId : InvokeMethodOnNull                                                                                                                                                                You cannot call a method on a null-valued expression.                                                   At C:\bin\BI_dat_tool.ps1:4605 char:3
+         $val = $item.toString()
+         ~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull

You cannot call a method on a null-valued expression.
At C:\bin\BI_dat_tool.ps1:4606 char:3
+         $attribs[$i] = $val.padLeft($max_len," ")
+         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull

You cannot call a method on a null-valued expression.
At C:\bin\BI_dat_tool.ps1:4605 char:3
+         $val = $item.toString()
+         ~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull

You cannot call a method on a null-valued expression.
At C:\bin\BI_dat_tool.ps1:4606 char:3
+         $attribs[$i] = $val.padLeft($max_len," ")
+         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull


Processed 3 DAT file(s)

Saved 18/18 available JPG file(s)

(Note: the following table is available as 'C:\BI_dat_tool\_output\output.csv')

File                                          Flags RO AgeHrs ImgsCnt ModelsUsed     LabelsFound AlertM
                                                                                                 emo
----                                          ----- -- ------ ------- ----------     ----------- ------
SidewalkRight.20240315_050000.1133879.3-3.dat    --       154       6 ipcam-combined person
SidewalkLeft.20240315_050000.1132087.5-0.dat     --       154       6 objects        person
OverviewPTZ.20240315_050000.1163169.5-0.dat      --       154       6 objects        person


PS C:\bin>
I'll try to upload V2 in the next few days. It fixes these null.string_function() errors while building the output table and CSV file.
it also:
  • supports filtering DAT files by Flag (i.e., protected, not protected, confirmed, not confirmed)
  • identifies the DAT file's confirmed image and extracts its associated AI memo
 
Last edited:
I assume I can ignore the warnings at the beginning (why invalid session, I specified "admin" password in config)
The script automatically saves the JSON login session ID so that it may be reused. The prior version of the script did not always recognize when the session id needed to be regenerated. Try deleting all *.txt files in this folder.

1711118867841.png
 
Script updated to V2. see post #1 to download the file

Key features of this new version are:
  • Supports filtering DAT files by Flag (i.e., protected, not protected, confirmed, not confirmed)
  • Identifies the DAT file's confirmed image and extracts its associated AI analysis memo
To view the entire changelog, open the script file in a script editor.

Flag Filtering examples:
Filter DATs for confirmed alerts only
bi_dat_tool.ps1 -Patterns "FD" -AgeHours 5300 -FilterFlags 'C' -SaveJPGs -SaveJSON -SingleFolder
Filter DATs for unconfirmed AND protected alerts
bi_dat_tool.ps1 -Patterns "FD" -AgeHours 5300 -FilterFlags '!C','P' -SaveJPGs -SaveJSON -SingleFolder

Screenshot #1 - shows the current usage guide
bi_dat_tool.ps1 -Help

V2_usage_guide.png

Screenshot #2 - shows changes to the console output

V2_output_console.png


Screenshot #3 - shows changes to the output CSV file

V2_output_csv.png
 
Last edited:
Using v2.0 now. Not seeing the EXIF related errors anymore. I assume I can ignore these warnings:
Code:
PS C:\bin> bi_dat_tool.ps1 -AgeHours 192 -SaveJPGs -SaveJSON -SingleFolder                                              
Loading DAT files (this may take awhile)...                                                                             
Found 41 DAT files matching Age >=192 hrs                                                                               
WARNING: JSON 'alertlist' response for 'SidewalkRight' has 162/1900 'clip'='@-1.jpg' entries; find w/ -DevMode          
WARNING: JSON 'alertlist' response for 'SidewalkLeft' has 149/1741 'clip'='@-1.jpg' entries; find w/ -DevMode          
WARNING: JSON 'alertlist' response for 'OverviewPTZ' has 151/1965 'clip'='@-1.jpg' entries; find w/ -DevMode           
WARNING: JSON 'alertlist' response for 'InteriorPT' has 57/394 'clip'='@-1.jpg' entries; find w/ -DevMode              
WARNING: JSON 'alertlist' response for 'GaragePTZ' has 93/1032 'clip'='@-1.jpg' entries; find w/ -DevMode
 
Using v2.0 now. Not seeing the EXIF related errors anymore. I assume I can ignore these warnings:
Code:
PS C:\bin> bi_dat_tool.ps1 -AgeHours 192 -SaveJPGs -SaveJSON -SingleFolder                                         
Loading DAT files (this may take awhile)...                                                                        
Found 41 DAT files matching Age >=192 hrs                                                                          
WARNING: JSON 'alertlist' response for 'SidewalkRight' has 162/1900 'clip'='@-1.jpg' entries; find w/ -DevMode     
WARNING: JSON 'alertlist' response for 'SidewalkLeft' has 149/1741 'clip'='@-1.jpg' entries; find w/ -DevMode     
WARNING: JSON 'alertlist' response for 'OverviewPTZ' has 151/1965 'clip'='@-1.jpg' entries; find w/ -DevMode      
WARNING: JSON 'alertlist' response for 'InteriorPT' has 57/394 'clip'='@-1.jpg' entries; find w/ -DevMode         
WARNING: JSON 'alertlist' response for 'GaragePTZ' has 93/1032 'clip'='@-1.jpg' entries; find w/ -DevMode
Thanks for the feedback.

Regarding the warnings, YES, you may ignore them. They are provided to let you know that some database records no longer have an associated BVR file. This is not a big deal for this utility.

BTW, if you wish to identify these records, you can use script argument -DevMode to save the Blue Iris JSON alertlist command responses to text files (*.json) that can be opened in a code editor (preferably one that has a json viewer option; e.g., NotePad++ has a nice JSON Viewer plugin).
 
  • Like
Reactions: actran
@jaydeel Using v2.0, I assumed if I use -FilterFlags 'C' option that only JPGs for confirmed are exported, right?
...but I see JPGs from OverviewPTZ cam in SingleFolder even when those are not confirmed.

Code:
PS C:\bin> bi_dat_tool.ps1 -SaveJPGs -SaveJSON -SingleFolder -FilterFlags 'C' -AgeHours 204 -Quiet

Processed 3 DAT file(s)

Saved 18/18 available JPG file(s)

File                                          Flags RO AgeHrs ImgsCnt ConfImg ModelsUsed     LabelsFound AlertMemoLabel
                                                                                                         s
----                                          ----- -- ------ ------- ------- ----------     ----------- --------------
SidewalkRight.20240315_050000.1133879.3-3.dat     C --    204       6         ipcam-combined person      person
SidewalkLeft.20240315_050000.1132087.5-0.dat      C --    204       6         objects        person      person
OverviewPTZ.20240315_050000.1163169.5-0.dat               204       6         objects        person

SingleFolder.png
 
Last edited:
@jaydeel Using v2.0, I assumed if I use -FilterFlags 'C' option that only JPGs for confirmed are exported, right?
...but I see JPGs from OverviewPTZ cam in SingleFolder even when those are not confirmed.

Code:
PS C:\bin> bi_dat_tool.ps1 -SaveJPGs -SaveJSON -SingleFolder -FilterFlags 'C' -AgeHours 204 -Quiet

Processed 3 DAT file(s)

Saved 18/18 available JPG file(s)

File                                          Flags RO AgeHrs ImgsCnt ConfImg ModelsUsed     LabelsFound AlertMemoLabel
                                                                                                         s
----                                          ----- -- ------ ------- ------- ----------     ----------- --------------
SidewalkRight.20240315_050000.1133879.3-3.dat     C --    204       6         ipcam-combined person      person
SidewalkLeft.20240315_050000.1132087.5-0.dat      C --    204       6         objects        person      person
OverviewPTZ.20240315_050000.1163169.5-0.dat               204       6         objects        person

View attachment 190360
Argument -FilterFlags 'C' applies to the database Confirmed flag, Using it means that DAT files for Unconfirmed alerts will not be inspected/extracted.

Am I understanding correctly that you want to extract ONLY the confirmed image from DAT files?
 
  • Like
Reactions: actran
Am I understanding correctly that you want to extract ONLY the confirmed image from DAT files?

Yes, that sounds more like what I am looking for.

BTW, thanks for sharing the details on -FilterFlags 'C' behavior. I wonder how there is a database confirm for those OverviewPTZ cam images when their confidence #'s are below my minimum? I don't feel like using those low confidence images as part of new training set.

Related, is there an option to extract ONLY the image with the asterisk from each DAT if that image is confirmed?
 
Last edited:
Related, is there an option to extract ONLY the image with the asterisk from each DAT if that image is confirmed?
Not currently. But it should be easy enough to add to V2.1.

I wonder how there is a database confirm for those OverviewPTZ cam images when their confidence #'s are below my minimum?
Are you saying the DAT files for these db-confirmed Alerts have no asterisked images when viewed in the Blue Iris DAT Viewer?

I don't feel like using those low confidence images as part of new training set.
If I correctly understand how the models work, you might want to use those currently low confidence images to create/improve the model for those classes of objects.
 
Last edited: