├── .gitignore ├── LICENSE ├── README.md ├── cal.html ├── cal_help.html ├── cal_options.html ├── fonts ├── fw_400 │ ├── cyrillic-ext.woff2 │ ├── cyrillic.woff2 │ ├── greek-ext.woff2 │ ├── greek.woff2 │ ├── latin-ext.woff2 │ ├── latin.woff2 │ └── vietnamese.woff2 ├── fw_600 │ ├── cyrillic-ext.woff2 │ ├── cyrillic.woff2 │ ├── greek-ext.woff2 │ ├── greek.woff2 │ ├── latin-ext.woff2 │ ├── latin.woff2 │ └── vietnamese.woff2 └── local_material_icons.woff2 ├── images ├── DICe_logo_white-01.png ├── checkerboard_diagram.png ├── dots_black_diagram.png ├── dots_diagram.png ├── icons │ ├── mac │ │ └── DICe.icns │ ├── png │ │ ├── icon_128x128.png │ │ ├── icon_128x128@2x.png │ │ ├── icon_16x16.png │ │ ├── icon_16x16@2x.png │ │ ├── icon_256x256.png │ │ ├── icon_256x256@2x.png │ │ ├── icon_32x32.png │ │ ├── icon_32x32@2x.png │ │ ├── icon_512x512.png │ │ └── icon_512x512@2x.png │ └── win │ │ └── DICe.ico ├── ui-icons_444444_256x240.png ├── ui-icons_555555_256x240.png ├── ui-icons_777620_256x240.png ├── ui-icons_777777_256x240.png ├── ui-icons_cc0000_256x240.png └── ui-icons_ffffff_256x240.png ├── index.html ├── jquery-ui.min.css ├── js ├── cal.js ├── cal_options.js ├── dice.js ├── file_utils.js ├── global.js ├── jquery-3.1.0.js ├── jquery-3.1.0.min.js ├── jquery-ui.js ├── jquery.min.js ├── live_plot.js ├── live_plot_line.js ├── live_plot_tracklib.js ├── live_plot_utils.js ├── loader.js ├── parser.js ├── plotly-mod.js ├── plotly-mod.min.js ├── preview.js ├── requires.js ├── show_tracking.js ├── utils.js └── viewer.js ├── main.js ├── material_icons.css ├── open_sans.css ├── package.json └── style.css /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | .dice-*.js 3 | .DS_Store 4 | .project 5 | .cproject 6 | .settings 7 | /node_modules -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | // ************************************************************************ 2 | // 3 | // Digital Image Correlation Engine (DICe) 4 | // Copyright 2015 Sandia Corporation. 5 | // 6 | // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, 7 | // the U.S. Government retains certain rights in this software. 8 | // 9 | // Redistribution and use in source and binary forms, with or without 10 | // modification, are permitted provided that the following conditions are 11 | // met: 12 | // 13 | // 1. Redistributions of source code must retain the above copyright 14 | // notice, this list of conditions and the following disclaimer. 15 | // 16 | // 2. Redistributions in binary form must reproduce the above copyright 17 | // notice, this list of conditions and the following disclaimer in the 18 | // documentation and/or other materials provided with the distribution. 19 | // 20 | // 3. Neither the name of the Corporation nor the names of the 21 | // contributors may be used to endorse or promote products derived from 22 | // this software without specific prior written permission. 23 | // 24 | // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY 25 | // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 27 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE 28 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 29 | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 30 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 31 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 32 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 33 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 34 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 | // 36 | // Questions? Contact: Dan Turner (dzturne@sandia.gov) 37 | // 38 | // ************************************************************************ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## DICe GUI 2 | 3 | The Electron-based desktop GUI for DICe (created with a combo of html, css, and javascript) 4 | 5 | ## Questions 6 | 7 | Contact: Dan Turner (dzturne@sandia.gov) 8 | 9 | ## License 10 | 11 | See LICENSE file -------------------------------------------------------------------------------- /cal.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Camera Calibration 6 | 12 | 13 | 14 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 |
35 | 36 |
37 |
38 |
FILE SELECTION
39 |
40 | 44 |
45 | 49 | 54 | 55 |
56 | 60 | 65 | 66 |
67 | 72 | 77 |
78 |
79 |
80 | folder 81 | image folder 82 |
83 |
84 | 85 |
86 |
image prefix
87 | 88 |
89 |
90 | stereo left prefix 93 |
94 |
95 | stereo right prefix 98 |
99 |
100 |
101 |
102 |
start index 103 |
104 |
end index 105 |
106 |
107 |
frame interval
108 | 109 |
110 |
111 | digits in number 114 |
115 |
116 |
119 | stereo left suffix 122 |
123 |
124 | stereo right suffix 127 |
128 |
129 |
extension
130 | 133 |
134 |
pose estimation frame
135 | 138 |
139 |
140 | check_circle 141 | preview 142 |
143 |
144 | include threshold 145 |
146 |
147 |
148 | 001 154 |
155 | 158 |
sample left cal image filename:
159 |
162 | 163 |
164 |
165 |
166 | 167 |
168 |
PATTERN OPTIONS
169 |
170 |
171 | 172 |
173 | 177 |
178 | save 179 | save target 180 |
181 |
182 | example checkerboard cal target 190 |
191 |
192 |
193 |

total pattern width

194 | 219 |
220 |
221 |

total pattern height

222 | 247 |
248 |
249 |
250 |
251 |

inner pattern width

252 | 263 |
264 |
265 |

inner pattern height

266 | 277 |
278 |
279 |
280 |
281 |

origin offset x

282 | 294 |
295 |
296 |

origin offset y

297 | 309 |
310 |
311 |
312 |
313 |
314 | settings 315 | cal options 316 |
317 |
318 | auto threshold 319 |
320 |
321 |
322 | pattern spacing
323 | 326 |
327 |
328 |
329 |
330 |
331 | use adaptive 332 |
333 |
334 |
335 |
336 |

337 | adaptive thresh constant: 338 |

339 | 342 |
343 |
344 |

345 | block size: 346 |

347 | 350 |
351 |
352 |

353 | thresholding constant: (counts) 354 |

355 | 358 |
359 |
360 |
361 | 362 |
365 |
CALIBRATION
366 |
367 | 368 |
371 | Console output:
372 |
373 |
374 |
377 | 378 | 379 | 380 |
383 | output file: 384 |
385 |
386 | rms error: 387 |
388 |
391 | avg epipolar error: 392 |
393 |
select files to skip (ctrl click 394 | to deselect):
395 |
396 |
    397 | 398 |
399 |
400 |
401 | 402 |
403 |
404 | 405 |
406 |
407 |
408 | PREVIEW 409 | LEFT 412 |
413 |
416 |
417 |
418 | 419 |
420 |
421 |
422 | 423 |
424 | 425 |
428 |
429 | PREVIEW 430 | RIGHT 433 |
434 |
437 |
438 |
439 | 440 |
441 |
442 |
443 | 444 |
445 | 446 |
447 | 448 | 449 | 451 | 452 |
453 | 454 | 455 | 456 | -------------------------------------------------------------------------------- /cal_help.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Calibration Help 6 | 12 | 13 | 14 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 |
29 |

Performing a Stereo or Single Camera Calibration

30 |

Select 'perform cal' to run a calibration given a set of images using the OpenCV 31 | calibration tools through DICe.

32 |

The first step in performing a calibration is selecting the image file folder. Once 33 | this folder is selected, DICe will attempt to automatically determine the file naming 34 | convention. If this fails, the components of the file naming convention need to be filled in 35 | manually. If the components of the naming convention are filled in correctly, an example 36 | image name will appear in green at the bottom of the first column on the calibration tool. 37 | If the name appears in red, this indicates that the file pattern is invalid. (note: all numbers 38 | in the filenames should be padded with zeros, for example if there are 10 images the image numbering 39 | should be _00 ... _10, not _0 ... _10, or for 100 images _000 ... _100, not _0 ... _100.)

40 |

The second step is to select the pattern parameters, beginning with the type of 41 | calibration plate that is used in the images. There are three options for this: 42 | checkerboard, black dots on a white background, and white dots on a black background. Once 43 | the pattern type is selected, the user must input the dimensions of the board, including the 44 | spacing size.

45 |

To preview the calibration marker extraction for a particular image, click the 46 | 'Preview' button in the left column of the tool. If the marker extraction is successful, the 47 | images will appear with a green border. A red border indicates a failed extraction.

48 |

For checkerboard patterns, there are thresholding options that can be adjusted. For dot 49 | patterns, the default thresholding used involves stepping through a series of constant 50 | binary threshold values until the marker dots can be extracted. The threshold setting can be 51 | changed by de-selecting the auto-threshold check box and setting the parameters.

52 |

If the calibration is successful, a cal.txt file will be created in the working 53 | directory. This file must then be loaded by pressing the 'accept' button in the calibration 54 | tool. An existing calibration file can be loaded using the 'load cal' menu option and 55 | selecting the file.

56 |

For a stereo calibration, the epipolar error should be less than 0.5 pixels. Large 57 | epipolar errors happen when one or more of the images introduces too much reprojection 58 | error. If this occurrs, look at the cal.log file in the working directory to see which 59 | images have the highest error. Through trial and error, eliminate images by selecting them 60 | in the list in the right column and re-running the calibration until the error is less than 0.5 pixels.

61 |

For single camera calibration, only the intrinsic parameters are estimated (such as the 62 | focal lengths, image centroids, etc). No reprojection error is calculated so there isn't a 63 | quality metric for the single camera calibration other than the RMS error.

64 |

Loading an Existing Calibration File

65 |

If the calibration has already been completed, or you would like to use an existing 66 | calibration file, select the 'load cal' menu option and select the desired file. DICe uses a 67 | specific xml format for calibration files, but can also read VIC3D xml files.

68 |

VIC3D XML Format

69 |

This is a format similar to the one used in a VIC3D .z3d file. Note that the 70 | orientations for each camera are not with respect to each other, but the origin between the 71 | two cameras. The file extension must be .xml for this format to be used (.z3d files must be 72 | unzipped. The .xml file from the archive can then be loaded in DICe)

73 | <calibration lri="calibration"> <camera id="0">182.694 74 | 184.935 2428.49 2431.72 3.39496 0.0881161 0 0 <orientation>-179.925 -14.7548 75 | 0.578387 1644 5.43174 970.919</orientation> </camera> <camera id="1">211.986 191.741 2479.9 2484.28 2.99616 76 | 0.112661 0 0 <orientation>179.77 14.7532 -0.617865 -1765.32 -49.9461 1075.75</orientation> </camera> </calibration> 77 |
78 |
79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /cal_options.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Camera Calibration Options 6 | 12 | 13 | 14 | 15 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 |
29 |
30 |
31 | fix intrinsic 32 |
33 |
Fix the values of fx, fy, cx, and cy based on 34 | the initial guess provided to OpenCV by the DICe calibration tool.
35 |
36 |
37 |
38 | use intrinsic guess 39 |
40 |
Begin with the initial values of fx, fy, cx, 41 | and cy provided to OpenCV then optimize further. Otherwise, (cx, cy) is initially set to the 42 | image center, and focal distances are computed in a least-squares fashion.
43 |
44 |
45 |
46 | use extrinsic guess 47 |
48 |
Begin with the initial values of the extrinsic 49 | parameters and optimize further.
50 |
51 |
52 |
53 | fix principal point 54 |
55 |
Use the image centroid as the principal point.
56 |
57 |
58 |
59 | fix aspect ratio 60 |
61 |
Only consider fy a free parameter, the 62 | ratio between fx and fy is fixed.
63 |
64 |
65 |
66 | same focal length 67 |
68 |
Constrain fx and fy to be the same.
69 |
70 |
71 |
72 | zero tangent dist 73 |
74 |
Set tangential distortions to zero.
75 |
76 |
77 |
78 | fix K1 79 |
80 |
Keep the K1 parameter constant during the 81 | optimization. If use_initial_guess is not active, K1 is set to 0. (Same for K2 and K3 if selected below)
82 |
83 |
84 | fix K2 85 |
86 |
87 | fix K3 88 |
89 | 92 | 95 |
96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /fonts/fw_400/cyrillic-ext.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dicengine/dicegui/5e881fc22f7d148f5a623f974d884062583a95a0/fonts/fw_400/cyrillic-ext.woff2 -------------------------------------------------------------------------------- /fonts/fw_400/cyrillic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dicengine/dicegui/5e881fc22f7d148f5a623f974d884062583a95a0/fonts/fw_400/cyrillic.woff2 -------------------------------------------------------------------------------- /fonts/fw_400/greek-ext.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dicengine/dicegui/5e881fc22f7d148f5a623f974d884062583a95a0/fonts/fw_400/greek-ext.woff2 -------------------------------------------------------------------------------- /fonts/fw_400/greek.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dicengine/dicegui/5e881fc22f7d148f5a623f974d884062583a95a0/fonts/fw_400/greek.woff2 -------------------------------------------------------------------------------- /fonts/fw_400/latin-ext.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dicengine/dicegui/5e881fc22f7d148f5a623f974d884062583a95a0/fonts/fw_400/latin-ext.woff2 -------------------------------------------------------------------------------- /fonts/fw_400/latin.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dicengine/dicegui/5e881fc22f7d148f5a623f974d884062583a95a0/fonts/fw_400/latin.woff2 -------------------------------------------------------------------------------- /fonts/fw_400/vietnamese.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dicengine/dicegui/5e881fc22f7d148f5a623f974d884062583a95a0/fonts/fw_400/vietnamese.woff2 -------------------------------------------------------------------------------- /fonts/fw_600/cyrillic-ext.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dicengine/dicegui/5e881fc22f7d148f5a623f974d884062583a95a0/fonts/fw_600/cyrillic-ext.woff2 -------------------------------------------------------------------------------- /fonts/fw_600/cyrillic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dicengine/dicegui/5e881fc22f7d148f5a623f974d884062583a95a0/fonts/fw_600/cyrillic.woff2 -------------------------------------------------------------------------------- /fonts/fw_600/greek-ext.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dicengine/dicegui/5e881fc22f7d148f5a623f974d884062583a95a0/fonts/fw_600/greek-ext.woff2 -------------------------------------------------------------------------------- /fonts/fw_600/greek.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dicengine/dicegui/5e881fc22f7d148f5a623f974d884062583a95a0/fonts/fw_600/greek.woff2 -------------------------------------------------------------------------------- /fonts/fw_600/latin-ext.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dicengine/dicegui/5e881fc22f7d148f5a623f974d884062583a95a0/fonts/fw_600/latin-ext.woff2 -------------------------------------------------------------------------------- /fonts/fw_600/latin.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dicengine/dicegui/5e881fc22f7d148f5a623f974d884062583a95a0/fonts/fw_600/latin.woff2 -------------------------------------------------------------------------------- /fonts/fw_600/vietnamese.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dicengine/dicegui/5e881fc22f7d148f5a623f974d884062583a95a0/fonts/fw_600/vietnamese.woff2 -------------------------------------------------------------------------------- /fonts/local_material_icons.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dicengine/dicegui/5e881fc22f7d148f5a623f974d884062583a95a0/fonts/local_material_icons.woff2 -------------------------------------------------------------------------------- /images/DICe_logo_white-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dicengine/dicegui/5e881fc22f7d148f5a623f974d884062583a95a0/images/DICe_logo_white-01.png -------------------------------------------------------------------------------- /images/checkerboard_diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dicengine/dicegui/5e881fc22f7d148f5a623f974d884062583a95a0/images/checkerboard_diagram.png -------------------------------------------------------------------------------- /images/dots_black_diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dicengine/dicegui/5e881fc22f7d148f5a623f974d884062583a95a0/images/dots_black_diagram.png -------------------------------------------------------------------------------- /images/dots_diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dicengine/dicegui/5e881fc22f7d148f5a623f974d884062583a95a0/images/dots_diagram.png -------------------------------------------------------------------------------- /images/icons/mac/DICe.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dicengine/dicegui/5e881fc22f7d148f5a623f974d884062583a95a0/images/icons/mac/DICe.icns -------------------------------------------------------------------------------- /images/icons/png/icon_128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dicengine/dicegui/5e881fc22f7d148f5a623f974d884062583a95a0/images/icons/png/icon_128x128.png -------------------------------------------------------------------------------- /images/icons/png/icon_128x128@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dicengine/dicegui/5e881fc22f7d148f5a623f974d884062583a95a0/images/icons/png/icon_128x128@2x.png -------------------------------------------------------------------------------- /images/icons/png/icon_16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dicengine/dicegui/5e881fc22f7d148f5a623f974d884062583a95a0/images/icons/png/icon_16x16.png -------------------------------------------------------------------------------- /images/icons/png/icon_16x16@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dicengine/dicegui/5e881fc22f7d148f5a623f974d884062583a95a0/images/icons/png/icon_16x16@2x.png -------------------------------------------------------------------------------- /images/icons/png/icon_256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dicengine/dicegui/5e881fc22f7d148f5a623f974d884062583a95a0/images/icons/png/icon_256x256.png -------------------------------------------------------------------------------- /images/icons/png/icon_256x256@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dicengine/dicegui/5e881fc22f7d148f5a623f974d884062583a95a0/images/icons/png/icon_256x256@2x.png -------------------------------------------------------------------------------- /images/icons/png/icon_32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dicengine/dicegui/5e881fc22f7d148f5a623f974d884062583a95a0/images/icons/png/icon_32x32.png -------------------------------------------------------------------------------- /images/icons/png/icon_32x32@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dicengine/dicegui/5e881fc22f7d148f5a623f974d884062583a95a0/images/icons/png/icon_32x32@2x.png -------------------------------------------------------------------------------- /images/icons/png/icon_512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dicengine/dicegui/5e881fc22f7d148f5a623f974d884062583a95a0/images/icons/png/icon_512x512.png -------------------------------------------------------------------------------- /images/icons/png/icon_512x512@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dicengine/dicegui/5e881fc22f7d148f5a623f974d884062583a95a0/images/icons/png/icon_512x512@2x.png -------------------------------------------------------------------------------- /images/icons/win/DICe.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dicengine/dicegui/5e881fc22f7d148f5a623f974d884062583a95a0/images/icons/win/DICe.ico -------------------------------------------------------------------------------- /images/ui-icons_444444_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dicengine/dicegui/5e881fc22f7d148f5a623f974d884062583a95a0/images/ui-icons_444444_256x240.png -------------------------------------------------------------------------------- /images/ui-icons_555555_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dicengine/dicegui/5e881fc22f7d148f5a623f974d884062583a95a0/images/ui-icons_555555_256x240.png -------------------------------------------------------------------------------- /images/ui-icons_777620_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dicengine/dicegui/5e881fc22f7d148f5a623f974d884062583a95a0/images/ui-icons_777620_256x240.png -------------------------------------------------------------------------------- /images/ui-icons_777777_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dicengine/dicegui/5e881fc22f7d148f5a623f974d884062583a95a0/images/ui-icons_777777_256x240.png -------------------------------------------------------------------------------- /images/ui-icons_cc0000_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dicengine/dicegui/5e881fc22f7d148f5a623f974d884062583a95a0/images/ui-icons_cc0000_256x240.png -------------------------------------------------------------------------------- /images/ui-icons_ffffff_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dicengine/dicegui/5e881fc22f7d148f5a623f974d884062583a95a0/images/ui-icons_ffffff_256x240.png -------------------------------------------------------------------------------- /jquery-ui.min.css: -------------------------------------------------------------------------------- 1 | /*! jQuery UI - v1.12.1 - 2016-09-14 2 | * http://jqueryui.com 3 | * Includes: core.css, accordion.css, autocomplete.css, menu.css, button.css, controlgroup.css, checkboxradio.css, datepicker.css, dialog.css, draggable.css, resizable.css, progressbar.css, selectable.css, selectmenu.css, slider.css, sortable.css, spinner.css, tabs.css, tooltip.css, theme.css 4 | * To view and modify this theme, visit http://jqueryui.com/themeroller/?bgShadowXPos=&bgOverlayXPos=&bgErrorXPos=&bgHighlightXPos=&bgContentXPos=&bgHeaderXPos=&bgActiveXPos=&bgHoverXPos=&bgDefaultXPos=&bgShadowYPos=&bgOverlayYPos=&bgErrorYPos=&bgHighlightYPos=&bgContentYPos=&bgHeaderYPos=&bgActiveYPos=&bgHoverYPos=&bgDefaultYPos=&bgShadowRepeat=&bgOverlayRepeat=&bgErrorRepeat=&bgHighlightRepeat=&bgContentRepeat=&bgHeaderRepeat=&bgActiveRepeat=&bgHoverRepeat=&bgDefaultRepeat=&iconsHover=url(%22images%2Fui-icons_555555_256x240.png%22)&iconsHighlight=url(%22images%2Fui-icons_777620_256x240.png%22)&iconsHeader=url(%22images%2Fui-icons_444444_256x240.png%22)&iconsError=url(%22images%2Fui-icons_cc0000_256x240.png%22)&iconsDefault=url(%22images%2Fui-icons_777777_256x240.png%22)&iconsContent=url(%22images%2Fui-icons_444444_256x240.png%22)&iconsActive=url(%22images%2Fui-icons_ffffff_256x240.png%22)&bgImgUrlShadow=&bgImgUrlOverlay=&bgImgUrlHover=&bgImgUrlHighlight=&bgImgUrlHeader=&bgImgUrlError=&bgImgUrlDefault=&bgImgUrlContent=&bgImgUrlActive=&opacityFilterShadow=Alpha(Opacity%3D30)&opacityFilterOverlay=Alpha(Opacity%3D30)&opacityShadowPerc=30&opacityOverlayPerc=30&iconColorHover=%23555555&iconColorHighlight=%23777620&iconColorHeader=%23444444&iconColorError=%23cc0000&iconColorDefault=%23777777&iconColorContent=%23444444&iconColorActive=%23ffffff&bgImgOpacityShadow=0&bgImgOpacityOverlay=0&bgImgOpacityError=95&bgImgOpacityHighlight=55&bgImgOpacityContent=75&bgImgOpacityHeader=75&bgImgOpacityActive=65&bgImgOpacityHover=75&bgImgOpacityDefault=75&bgTextureShadow=flat&bgTextureOverlay=flat&bgTextureError=flat&bgTextureHighlight=flat&bgTextureContent=flat&bgTextureHeader=flat&bgTextureActive=flat&bgTextureHover=flat&bgTextureDefault=flat&cornerRadius=3px&fwDefault=normal&ffDefault=Arial%2CHelvetica%2Csans-serif&fsDefault=1em&cornerRadiusShadow=8px&thicknessShadow=5px&offsetLeftShadow=0px&offsetTopShadow=0px&opacityShadow=.3&bgColorShadow=%23666666&opacityOverlay=.3&bgColorOverlay=%23aaaaaa&fcError=%235f3f3f&borderColorError=%23f1a899&bgColorError=%23fddfdf&fcHighlight=%23777620&borderColorHighlight=%23dad55e&bgColorHighlight=%23fffa90&fcContent=%23333333&borderColorContent=%23dddddd&bgColorContent=%23ffffff&fcHeader=%23333333&borderColorHeader=%23dddddd&bgColorHeader=%23e9e9e9&fcActive=%23ffffff&borderColorActive=%23003eff&bgColorActive=%23007fff&fcHover=%232b2b2b&borderColorHover=%23cccccc&bgColorHover=%23ededed&fcDefault=%23454545&borderColorDefault=%23c5c5c5&bgColorDefault=%23f6f6f6 5 | * Copyright jQuery Foundation and other contributors; Licensed MIT */ 6 | 7 | .ui-helper-hidden{display:none}.ui-helper-hidden-accessible{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.ui-helper-reset{margin:0;padding:0;border:0;outline:0;line-height:1.3;text-decoration:none;font-size:100%;list-style:none}.ui-helper-clearfix:before,.ui-helper-clearfix:after{content:"";display:table;border-collapse:collapse}.ui-helper-clearfix:after{clear:both}.ui-helper-zfix{width:100%;height:100%;top:0;left:0;position:absolute;opacity:0;filter:Alpha(Opacity=0)}.ui-front{z-index:100}.ui-state-disabled{cursor:default!important;pointer-events:none}.ui-icon{display:inline-block;vertical-align:middle;margin-top:-.25em;position:relative;text-indent:-99999px;overflow:hidden;background-repeat:no-repeat}.ui-widget-icon-block{left:50%;margin-left:-8px;display:block}.ui-widget-overlay{position:fixed;top:0;left:0;width:100%;height:100%}.ui-accordion .ui-accordion-header{display:block;cursor:pointer;position:relative;margin:2px 0 0 0;padding:.5em .5em .5em .7em;font-size:100%}.ui-accordion .ui-accordion-content{padding:1em 2.2em;border-top:0;overflow:auto}.ui-autocomplete{position:absolute;top:0;left:0;cursor:default}.ui-menu{list-style:none;padding:0;margin:0;display:block;outline:0}.ui-menu .ui-menu{position:absolute}.ui-menu .ui-menu-item{margin:0;cursor:pointer;list-style-image:url("data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7")}.ui-menu .ui-menu-item-wrapper{position:relative;padding:3px 1em 3px .4em}.ui-menu .ui-menu-divider{margin:5px 0;height:0;font-size:0;line-height:0;border-width:1px 0 0 0}.ui-menu .ui-state-focus,.ui-menu .ui-state-active{margin:-1px}.ui-menu-icons{position:relative}.ui-menu-icons .ui-menu-item-wrapper{padding-left:2em}.ui-menu .ui-icon{position:absolute;top:0;bottom:0;left:.2em;margin:auto 0}.ui-menu .ui-menu-icon{left:auto;right:0}.ui-button{padding:.4em 1em;display:inline-block;position:relative;line-height:normal;margin-right:.1em;cursor:pointer;vertical-align:middle;text-align:center;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;overflow:visible}.ui-button,.ui-button:link,.ui-button:visited,.ui-button:hover,.ui-button:active{text-decoration:none}.ui-button-icon-only{width:2em;box-sizing:border-box;text-indent:-9999px;white-space:nowrap}input.ui-button.ui-button-icon-only{text-indent:0}.ui-button-icon-only .ui-icon{position:absolute;top:50%;left:50%;margin-top:-8px;margin-left:-8px}.ui-button.ui-icon-notext .ui-icon{padding:0;width:2.1em;height:2.1em;text-indent:-9999px;white-space:nowrap}input.ui-button.ui-icon-notext .ui-icon{width:auto;height:auto;text-indent:0;white-space:normal;padding:.4em 1em}input.ui-button::-moz-focus-inner,button.ui-button::-moz-focus-inner{border:0;padding:0}.ui-controlgroup{vertical-align:middle;display:inline-block}.ui-controlgroup > .ui-controlgroup-item{float:left;margin-left:0;margin-right:0}.ui-controlgroup > .ui-controlgroup-item:focus,.ui-controlgroup > .ui-controlgroup-item.ui-visual-focus{z-index:9999}.ui-controlgroup-vertical > .ui-controlgroup-item{display:block;float:none;width:100%;margin-top:0;margin-bottom:0;text-align:left}.ui-controlgroup-vertical .ui-controlgroup-item{box-sizing:border-box}.ui-controlgroup .ui-controlgroup-label{padding:.4em 1em}.ui-controlgroup .ui-controlgroup-label span{font-size:80%}.ui-controlgroup-horizontal .ui-controlgroup-label + .ui-controlgroup-item{border-left:none}.ui-controlgroup-vertical .ui-controlgroup-label + .ui-controlgroup-item{border-top:none}.ui-controlgroup-horizontal .ui-controlgroup-label.ui-widget-content{border-right:none}.ui-controlgroup-vertical .ui-controlgroup-label.ui-widget-content{border-bottom:none}.ui-controlgroup-vertical .ui-spinner-input{width:75%;width:calc( 100% - 2.4em )}.ui-controlgroup-vertical .ui-spinner .ui-spinner-up{border-top-style:solid}.ui-checkboxradio-label .ui-icon-background{box-shadow:inset 1px 1px 1px #ccc;border-radius:.12em;border:none}.ui-checkboxradio-radio-label .ui-icon-background{width:16px;height:16px;border-radius:1em;overflow:visible;border:none}.ui-checkboxradio-radio-label.ui-checkboxradio-checked .ui-icon,.ui-checkboxradio-radio-label.ui-checkboxradio-checked:hover .ui-icon{background-image:none;width:8px;height:8px;border-width:4px;border-style:solid}.ui-checkboxradio-disabled{pointer-events:none}.ui-datepicker{width:17em;padding:.2em .2em 0;display:none}.ui-datepicker .ui-datepicker-header{position:relative;padding:.2em 0}.ui-datepicker .ui-datepicker-prev,.ui-datepicker .ui-datepicker-next{position:absolute;top:2px;width:1.8em;height:1.8em}.ui-datepicker .ui-datepicker-prev-hover,.ui-datepicker .ui-datepicker-next-hover{top:1px}.ui-datepicker .ui-datepicker-prev{left:2px}.ui-datepicker .ui-datepicker-next{right:2px}.ui-datepicker .ui-datepicker-prev-hover{left:1px}.ui-datepicker .ui-datepicker-next-hover{right:1px}.ui-datepicker .ui-datepicker-prev span,.ui-datepicker .ui-datepicker-next span{display:block;position:absolute;left:50%;margin-left:-8px;top:50%;margin-top:-8px}.ui-datepicker .ui-datepicker-title{margin:0 2.3em;line-height:1.8em;text-align:center}.ui-datepicker .ui-datepicker-title select{font-size:1em;margin:1px 0}.ui-datepicker select.ui-datepicker-month,.ui-datepicker select.ui-datepicker-year{width:45%}.ui-datepicker table{width:100%;font-size:.9em;border-collapse:collapse;margin:0 0 .4em}.ui-datepicker th{padding:.7em .3em;text-align:center;font-weight:bold;border:0}.ui-datepicker td{border:0;padding:1px}.ui-datepicker td span,.ui-datepicker td a{display:block;padding:.2em;text-align:right;text-decoration:none}.ui-datepicker .ui-datepicker-buttonpane{background-image:none;margin:.7em 0 0 0;padding:0 .2em;border-left:0;border-right:0;border-bottom:0}.ui-datepicker .ui-datepicker-buttonpane button{float:right;margin:.5em .2em .4em;cursor:pointer;padding:.2em .6em .3em .6em;width:auto;overflow:visible}.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current{float:left}.ui-datepicker.ui-datepicker-multi{width:auto}.ui-datepicker-multi .ui-datepicker-group{float:left}.ui-datepicker-multi .ui-datepicker-group table{width:95%;margin:0 auto .4em}.ui-datepicker-multi-2 .ui-datepicker-group{width:50%}.ui-datepicker-multi-3 .ui-datepicker-group{width:33.3%}.ui-datepicker-multi-4 .ui-datepicker-group{width:25%}.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header,.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header{border-left-width:0}.ui-datepicker-multi .ui-datepicker-buttonpane{clear:left}.ui-datepicker-row-break{clear:both;width:100%;font-size:0}.ui-datepicker-rtl{direction:rtl}.ui-datepicker-rtl .ui-datepicker-prev{right:2px;left:auto}.ui-datepicker-rtl .ui-datepicker-next{left:2px;right:auto}.ui-datepicker-rtl .ui-datepicker-prev:hover{right:1px;left:auto}.ui-datepicker-rtl .ui-datepicker-next:hover{left:1px;right:auto}.ui-datepicker-rtl .ui-datepicker-buttonpane{clear:right}.ui-datepicker-rtl .ui-datepicker-buttonpane button{float:left}.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current,.ui-datepicker-rtl .ui-datepicker-group{float:right}.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header,.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header{border-right-width:0;border-left-width:1px}.ui-datepicker .ui-icon{display:block;text-indent:-99999px;overflow:hidden;background-repeat:no-repeat;left:.5em;top:.3em}.ui-dialog{position:absolute;top:0;left:0;padding:.2em;outline:0}.ui-dialog .ui-dialog-titlebar{padding:.4em 1em;position:relative}.ui-dialog .ui-dialog-title{float:left;margin:.1em 0;white-space:nowrap;width:90%;overflow:hidden;text-overflow:ellipsis}.ui-dialog .ui-dialog-titlebar-close{position:absolute;right:.3em;top:50%;width:20px;margin:-10px 0 0 0;padding:1px;height:20px}.ui-dialog .ui-dialog-content{position:relative;border:0;padding:.5em 1em;background:none;overflow:auto}.ui-dialog .ui-dialog-buttonpane{text-align:left;border-width:1px 0 0 0;background-image:none;margin-top:.5em;padding:.3em 1em .5em .4em}.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset{float:right}.ui-dialog .ui-dialog-buttonpane button{margin:.5em .4em .5em 0;cursor:pointer}.ui-dialog .ui-resizable-n{height:2px;top:0}.ui-dialog .ui-resizable-e{width:2px;right:0}.ui-dialog .ui-resizable-s{height:2px;bottom:0}.ui-dialog .ui-resizable-w{width:2px;left:0}.ui-dialog .ui-resizable-se,.ui-dialog .ui-resizable-sw,.ui-dialog .ui-resizable-ne,.ui-dialog .ui-resizable-nw{width:7px;height:7px}.ui-dialog .ui-resizable-se{right:0;bottom:0}.ui-dialog .ui-resizable-sw{left:0;bottom:0}.ui-dialog .ui-resizable-ne{right:0;top:0}.ui-dialog .ui-resizable-nw{left:0;top:0}.ui-draggable .ui-dialog-titlebar{cursor:move}.ui-draggable-handle{-ms-touch-action:none;touch-action:none}.ui-resizable{position:relative}.ui-resizable-handle{position:absolute;font-size:0.1px;display:block;-ms-touch-action:none;touch-action:none}.ui-resizable-disabled .ui-resizable-handle,.ui-resizable-autohide .ui-resizable-handle{display:none}.ui-resizable-n{cursor:n-resize;height:7px;width:100%;top:-5px;left:0}.ui-resizable-s{cursor:s-resize;height:7px;width:100%;bottom:-5px;left:0}.ui-resizable-e{cursor:e-resize;width:7px;right:-5px;top:0;height:100%}.ui-resizable-w{cursor:w-resize;width:7px;left:-5px;top:0;height:100%}.ui-resizable-se{cursor:se-resize;width:12px;height:12px;right:1px;bottom:1px}.ui-resizable-sw{cursor:sw-resize;width:9px;height:9px;left:-5px;bottom:-5px}.ui-resizable-nw{cursor:nw-resize;width:9px;height:9px;left:-5px;top:-5px}.ui-resizable-ne{cursor:ne-resize;width:9px;height:9px;right:-5px;top:-5px}.ui-progressbar{height:2em;text-align:left;overflow:hidden}.ui-progressbar .ui-progressbar-value{margin:-1px;height:100%}.ui-progressbar .ui-progressbar-overlay{background:url("data:image/gif;base64,R0lGODlhKAAoAIABAAAAAP///yH/C05FVFNDQVBFMi4wAwEAAAAh+QQJAQABACwAAAAAKAAoAAACkYwNqXrdC52DS06a7MFZI+4FHBCKoDeWKXqymPqGqxvJrXZbMx7Ttc+w9XgU2FB3lOyQRWET2IFGiU9m1frDVpxZZc6bfHwv4c1YXP6k1Vdy292Fb6UkuvFtXpvWSzA+HycXJHUXiGYIiMg2R6W459gnWGfHNdjIqDWVqemH2ekpObkpOlppWUqZiqr6edqqWQAAIfkECQEAAQAsAAAAACgAKAAAApSMgZnGfaqcg1E2uuzDmmHUBR8Qil95hiPKqWn3aqtLsS18y7G1SzNeowWBENtQd+T1JktP05nzPTdJZlR6vUxNWWjV+vUWhWNkWFwxl9VpZRedYcflIOLafaa28XdsH/ynlcc1uPVDZxQIR0K25+cICCmoqCe5mGhZOfeYSUh5yJcJyrkZWWpaR8doJ2o4NYq62lAAACH5BAkBAAEALAAAAAAoACgAAAKVDI4Yy22ZnINRNqosw0Bv7i1gyHUkFj7oSaWlu3ovC8GxNso5fluz3qLVhBVeT/Lz7ZTHyxL5dDalQWPVOsQWtRnuwXaFTj9jVVh8pma9JjZ4zYSj5ZOyma7uuolffh+IR5aW97cHuBUXKGKXlKjn+DiHWMcYJah4N0lYCMlJOXipGRr5qdgoSTrqWSq6WFl2ypoaUAAAIfkECQEAAQAsAAAAACgAKAAAApaEb6HLgd/iO7FNWtcFWe+ufODGjRfoiJ2akShbueb0wtI50zm02pbvwfWEMWBQ1zKGlLIhskiEPm9R6vRXxV4ZzWT2yHOGpWMyorblKlNp8HmHEb/lCXjcW7bmtXP8Xt229OVWR1fod2eWqNfHuMjXCPkIGNileOiImVmCOEmoSfn3yXlJWmoHGhqp6ilYuWYpmTqKUgAAIfkECQEAAQAsAAAAACgAKAAAApiEH6kb58biQ3FNWtMFWW3eNVcojuFGfqnZqSebuS06w5V80/X02pKe8zFwP6EFWOT1lDFk8rGERh1TTNOocQ61Hm4Xm2VexUHpzjymViHrFbiELsefVrn6XKfnt2Q9G/+Xdie499XHd2g4h7ioOGhXGJboGAnXSBnoBwKYyfioubZJ2Hn0RuRZaflZOil56Zp6iioKSXpUAAAh+QQJAQABACwAAAAAKAAoAAACkoQRqRvnxuI7kU1a1UU5bd5tnSeOZXhmn5lWK3qNTWvRdQxP8qvaC+/yaYQzXO7BMvaUEmJRd3TsiMAgswmNYrSgZdYrTX6tSHGZO73ezuAw2uxuQ+BbeZfMxsexY35+/Qe4J1inV0g4x3WHuMhIl2jXOKT2Q+VU5fgoSUI52VfZyfkJGkha6jmY+aaYdirq+lQAACH5BAkBAAEALAAAAAAoACgAAAKWBIKpYe0L3YNKToqswUlvznigd4wiR4KhZrKt9Upqip61i9E3vMvxRdHlbEFiEXfk9YARYxOZZD6VQ2pUunBmtRXo1Lf8hMVVcNl8JafV38aM2/Fu5V16Bn63r6xt97j09+MXSFi4BniGFae3hzbH9+hYBzkpuUh5aZmHuanZOZgIuvbGiNeomCnaxxap2upaCZsq+1kAACH5BAkBAAEALAAAAAAoACgAAAKXjI8By5zf4kOxTVrXNVlv1X0d8IGZGKLnNpYtm8Lr9cqVeuOSvfOW79D9aDHizNhDJidFZhNydEahOaDH6nomtJjp1tutKoNWkvA6JqfRVLHU/QUfau9l2x7G54d1fl995xcIGAdXqMfBNadoYrhH+Mg2KBlpVpbluCiXmMnZ2Sh4GBqJ+ckIOqqJ6LmKSllZmsoq6wpQAAAh+QQJAQABACwAAAAAKAAoAAAClYx/oLvoxuJDkU1a1YUZbJ59nSd2ZXhWqbRa2/gF8Gu2DY3iqs7yrq+xBYEkYvFSM8aSSObE+ZgRl1BHFZNr7pRCavZ5BW2142hY3AN/zWtsmf12p9XxxFl2lpLn1rseztfXZjdIWIf2s5dItwjYKBgo9yg5pHgzJXTEeGlZuenpyPmpGQoKOWkYmSpaSnqKileI2FAAACH5BAkBAAEALAAAAAAoACgAAAKVjB+gu+jG4kORTVrVhRlsnn2dJ3ZleFaptFrb+CXmO9OozeL5VfP99HvAWhpiUdcwkpBH3825AwYdU8xTqlLGhtCosArKMpvfa1mMRae9VvWZfeB2XfPkeLmm18lUcBj+p5dnN8jXZ3YIGEhYuOUn45aoCDkp16hl5IjYJvjWKcnoGQpqyPlpOhr3aElaqrq56Bq7VAAAOw==");height:100%;filter:alpha(opacity=25);opacity:0.25}.ui-progressbar-indeterminate .ui-progressbar-value{background-image:none}.ui-selectable{-ms-touch-action:none;touch-action:none}.ui-selectable-helper{position:absolute;z-index:100;border:1px dotted black}.ui-selectmenu-menu{padding:0;margin:0;position:absolute;top:0;left:0;display:none}.ui-selectmenu-menu .ui-menu{overflow:auto;overflow-x:hidden;padding-bottom:1px}.ui-selectmenu-menu .ui-menu .ui-selectmenu-optgroup{font-size:1em;font-weight:bold;line-height:1.5;padding:2px 0.4em;margin:0.5em 0 0 0;height:auto;border:0}.ui-selectmenu-open{display:block}.ui-selectmenu-text{display:block;margin-right:20px;overflow:hidden;text-overflow:ellipsis}.ui-selectmenu-button.ui-button{text-align:left;white-space:nowrap;width:14em}.ui-selectmenu-icon.ui-icon{float:right;margin-top:0}.ui-slider{position:relative;text-align:left}.ui-slider .ui-slider-handle{position:absolute;z-index:2;width:1.2em;height:1.2em;cursor:default;-ms-touch-action:none;touch-action:none}.ui-slider .ui-slider-range{position:absolute;z-index:1;font-size:.7em;display:block;border:0;background-position:0 0}.ui-slider.ui-state-disabled .ui-slider-handle,.ui-slider.ui-state-disabled .ui-slider-range{filter:inherit}.ui-slider-horizontal{height:.8em}.ui-slider-horizontal .ui-slider-handle{top:-.3em;margin-left:-.6em}.ui-slider-horizontal .ui-slider-range{top:0;height:100%}.ui-slider-horizontal .ui-slider-range-min{left:0}.ui-slider-horizontal .ui-slider-range-max{right:0}.ui-slider-vertical{width:.8em;height:100px}.ui-slider-vertical .ui-slider-handle{left:-.3em;margin-left:0;margin-bottom:-.6em}.ui-slider-vertical .ui-slider-range{left:0;width:100%}.ui-slider-vertical .ui-slider-range-min{bottom:0}.ui-slider-vertical .ui-slider-range-max{top:0}.ui-sortable-handle{-ms-touch-action:none;touch-action:none}.ui-spinner{position:relative;display:inline-block;overflow:hidden;padding:0;vertical-align:middle}.ui-spinner-input{border:none;background:none;color:inherit;padding:.222em 0;margin:.2em 0;vertical-align:middle;margin-left:.4em;margin-right:2em}.ui-spinner-button{width:1.6em;height:50%;font-size:.5em;padding:0;margin:0;text-align:center;position:absolute;cursor:default;display:block;overflow:hidden;right:0}.ui-spinner a.ui-spinner-button{border-top-style:none;border-bottom-style:none;border-right-style:none}.ui-spinner-up{top:0}.ui-spinner-down{bottom:0}.ui-tabs{position:relative;padding:.2em}.ui-tabs .ui-tabs-nav{margin:0;padding:.2em .2em 0}.ui-tabs .ui-tabs-nav li{list-style:none;float:left;position:relative;top:0;margin:1px .2em 0 0;border-bottom-width:0;padding:0;white-space:nowrap}.ui-tabs .ui-tabs-nav .ui-tabs-anchor{float:left;padding:.5em 1em;text-decoration:none}.ui-tabs .ui-tabs-nav li.ui-tabs-active{margin-bottom:-1px;padding-bottom:1px}.ui-tabs .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor,.ui-tabs .ui-tabs-nav li.ui-state-disabled .ui-tabs-anchor,.ui-tabs .ui-tabs-nav li.ui-tabs-loading .ui-tabs-anchor{cursor:text}.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor{cursor:pointer}.ui-tabs .ui-tabs-panel{display:block;border-width:0;padding:1em 1.4em;background:none}.ui-tooltip{padding:8px;position:absolute;z-index:9999;max-width:300px}body .ui-tooltip{border-width:2px}.ui-widget{font-family:Arial,Helvetica,sans-serif;font-size:1em}.ui-widget .ui-widget{font-size:1em}.ui-widget input,.ui-widget select,.ui-widget textarea,.ui-widget button{font-family:Arial,Helvetica,sans-serif;font-size:1em}.ui-widget.ui-widget-content{border:1px solid #c5c5c5}.ui-widget-content{border:1px solid #ddd;background:#fff;color:#333}.ui-widget-content a{color:#333}.ui-widget-header{border:1px solid #ddd;background:#e9e9e9;color:#333;font-weight:bold}.ui-widget-header a{color:#333}.ui-state-default,.ui-widget-content .ui-state-default,.ui-widget-header .ui-state-default,.ui-button,html .ui-button.ui-state-disabled:hover,html .ui-button.ui-state-disabled:active{border:1px solid #c5c5c5;background:#f6f6f6;font-weight:normal;color:#454545}.ui-state-default a,.ui-state-default a:link,.ui-state-default a:visited,a.ui-button,a:link.ui-button,a:visited.ui-button,.ui-button{color:#454545;text-decoration:none}.ui-state-hover,.ui-widget-content .ui-state-hover,.ui-widget-header .ui-state-hover,.ui-state-focus,.ui-widget-content .ui-state-focus,.ui-widget-header .ui-state-focus,.ui-button:hover,.ui-button:focus{border:1px solid #ccc;background:#ededed;font-weight:normal;color:#2b2b2b}.ui-state-hover a,.ui-state-hover a:hover,.ui-state-hover a:link,.ui-state-hover a:visited,.ui-state-focus a,.ui-state-focus a:hover,.ui-state-focus a:link,.ui-state-focus a:visited,a.ui-button:hover,a.ui-button:focus{color:#2b2b2b;text-decoration:none}.ui-visual-focus{box-shadow:0 0 3px 1px rgb(94,158,214)}.ui-state-active,.ui-widget-content .ui-state-active,.ui-widget-header .ui-state-active,a.ui-button:active,.ui-button:active,.ui-button.ui-state-active:hover{border:1px solid #003eff;background:#007fff;font-weight:normal;color:#fff}.ui-icon-background,.ui-state-active .ui-icon-background{border:#003eff;background-color:#fff}.ui-state-active a,.ui-state-active a:link,.ui-state-active a:visited{color:#fff;text-decoration:none}.ui-state-highlight,.ui-widget-content .ui-state-highlight,.ui-widget-header .ui-state-highlight{border:1px solid #dad55e;background:#fffa90;color:#777620}.ui-state-checked{border:1px solid #dad55e;background:#fffa90}.ui-state-highlight a,.ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a{color:#777620}.ui-state-error,.ui-widget-content .ui-state-error,.ui-widget-header .ui-state-error{border:1px solid #f1a899;background:#fddfdf;color:#5f3f3f}.ui-state-error a,.ui-widget-content .ui-state-error a,.ui-widget-header .ui-state-error a{color:#5f3f3f}.ui-state-error-text,.ui-widget-content .ui-state-error-text,.ui-widget-header .ui-state-error-text{color:#5f3f3f}.ui-priority-primary,.ui-widget-content .ui-priority-primary,.ui-widget-header .ui-priority-primary{font-weight:bold}.ui-priority-secondary,.ui-widget-content .ui-priority-secondary,.ui-widget-header .ui-priority-secondary{opacity:.7;filter:Alpha(Opacity=70);font-weight:normal}.ui-state-disabled,.ui-widget-content .ui-state-disabled,.ui-widget-header .ui-state-disabled{opacity:.35;filter:Alpha(Opacity=35);background-image:none}.ui-state-disabled .ui-icon{filter:Alpha(Opacity=35)}.ui-icon{width:16px;height:16px}.ui-icon,.ui-widget-content .ui-icon{background-image:url("images/ui-icons_444444_256x240.png")}.ui-widget-header .ui-icon{background-image:url("images/ui-icons_444444_256x240.png")}.ui-state-hover .ui-icon,.ui-state-focus .ui-icon,.ui-button:hover .ui-icon,.ui-button:focus .ui-icon{background-image:url("images/ui-icons_555555_256x240.png")}.ui-state-active .ui-icon,.ui-button:active .ui-icon{background-image:url("images/ui-icons_ffffff_256x240.png")}.ui-state-highlight .ui-icon,.ui-button .ui-state-highlight.ui-icon{background-image:url("images/ui-icons_777620_256x240.png")}.ui-state-error .ui-icon,.ui-state-error-text .ui-icon{background-image:url("images/ui-icons_cc0000_256x240.png")}.ui-button .ui-icon{background-image:url("images/ui-icons_777777_256x240.png")}.ui-icon-blank{background-position:16px 16px}.ui-icon-caret-1-n{background-position:0 0}.ui-icon-caret-1-ne{background-position:-16px 0}.ui-icon-caret-1-e{background-position:-32px 0}.ui-icon-caret-1-se{background-position:-48px 0}.ui-icon-caret-1-s{background-position:-65px 0}.ui-icon-caret-1-sw{background-position:-80px 0}.ui-icon-caret-1-w{background-position:-96px 0}.ui-icon-caret-1-nw{background-position:-112px 0}.ui-icon-caret-2-n-s{background-position:-128px 0}.ui-icon-caret-2-e-w{background-position:-144px 0}.ui-icon-triangle-1-n{background-position:0 -16px}.ui-icon-triangle-1-ne{background-position:-16px -16px}.ui-icon-triangle-1-e{background-position:-32px -16px}.ui-icon-triangle-1-se{background-position:-48px -16px}.ui-icon-triangle-1-s{background-position:-65px -16px}.ui-icon-triangle-1-sw{background-position:-80px -16px}.ui-icon-triangle-1-w{background-position:-96px -16px}.ui-icon-triangle-1-nw{background-position:-112px -16px}.ui-icon-triangle-2-n-s{background-position:-128px -16px}.ui-icon-triangle-2-e-w{background-position:-144px -16px}.ui-icon-arrow-1-n{background-position:0 -32px}.ui-icon-arrow-1-ne{background-position:-16px -32px}.ui-icon-arrow-1-e{background-position:-32px -32px}.ui-icon-arrow-1-se{background-position:-48px -32px}.ui-icon-arrow-1-s{background-position:-65px -32px}.ui-icon-arrow-1-sw{background-position:-80px -32px}.ui-icon-arrow-1-w{background-position:-96px -32px}.ui-icon-arrow-1-nw{background-position:-112px -32px}.ui-icon-arrow-2-n-s{background-position:-128px -32px}.ui-icon-arrow-2-ne-sw{background-position:-144px -32px}.ui-icon-arrow-2-e-w{background-position:-160px -32px}.ui-icon-arrow-2-se-nw{background-position:-176px -32px}.ui-icon-arrowstop-1-n{background-position:-192px -32px}.ui-icon-arrowstop-1-e{background-position:-208px -32px}.ui-icon-arrowstop-1-s{background-position:-224px -32px}.ui-icon-arrowstop-1-w{background-position:-240px -32px}.ui-icon-arrowthick-1-n{background-position:1px -48px}.ui-icon-arrowthick-1-ne{background-position:-16px -48px}.ui-icon-arrowthick-1-e{background-position:-32px -48px}.ui-icon-arrowthick-1-se{background-position:-48px -48px}.ui-icon-arrowthick-1-s{background-position:-64px -48px}.ui-icon-arrowthick-1-sw{background-position:-80px -48px}.ui-icon-arrowthick-1-w{background-position:-96px -48px}.ui-icon-arrowthick-1-nw{background-position:-112px -48px}.ui-icon-arrowthick-2-n-s{background-position:-128px -48px}.ui-icon-arrowthick-2-ne-sw{background-position:-144px -48px}.ui-icon-arrowthick-2-e-w{background-position:-160px -48px}.ui-icon-arrowthick-2-se-nw{background-position:-176px -48px}.ui-icon-arrowthickstop-1-n{background-position:-192px -48px}.ui-icon-arrowthickstop-1-e{background-position:-208px -48px}.ui-icon-arrowthickstop-1-s{background-position:-224px -48px}.ui-icon-arrowthickstop-1-w{background-position:-240px -48px}.ui-icon-arrowreturnthick-1-w{background-position:0 -64px}.ui-icon-arrowreturnthick-1-n{background-position:-16px -64px}.ui-icon-arrowreturnthick-1-e{background-position:-32px -64px}.ui-icon-arrowreturnthick-1-s{background-position:-48px -64px}.ui-icon-arrowreturn-1-w{background-position:-64px -64px}.ui-icon-arrowreturn-1-n{background-position:-80px -64px}.ui-icon-arrowreturn-1-e{background-position:-96px -64px}.ui-icon-arrowreturn-1-s{background-position:-112px -64px}.ui-icon-arrowrefresh-1-w{background-position:-128px -64px}.ui-icon-arrowrefresh-1-n{background-position:-144px -64px}.ui-icon-arrowrefresh-1-e{background-position:-160px -64px}.ui-icon-arrowrefresh-1-s{background-position:-176px -64px}.ui-icon-arrow-4{background-position:0 -80px}.ui-icon-arrow-4-diag{background-position:-16px -80px}.ui-icon-extlink{background-position:-32px -80px}.ui-icon-newwin{background-position:-48px -80px}.ui-icon-refresh{background-position:-64px -80px}.ui-icon-shuffle{background-position:-80px -80px}.ui-icon-transfer-e-w{background-position:-96px -80px}.ui-icon-transferthick-e-w{background-position:-112px -80px}.ui-icon-folder-collapsed{background-position:0 -96px}.ui-icon-folder-open{background-position:-16px -96px}.ui-icon-document{background-position:-32px -96px}.ui-icon-document-b{background-position:-48px -96px}.ui-icon-note{background-position:-64px -96px}.ui-icon-mail-closed{background-position:-80px -96px}.ui-icon-mail-open{background-position:-96px -96px}.ui-icon-suitcase{background-position:-112px -96px}.ui-icon-comment{background-position:-128px -96px}.ui-icon-person{background-position:-144px -96px}.ui-icon-print{background-position:-160px -96px}.ui-icon-trash{background-position:-176px -96px}.ui-icon-locked{background-position:-192px -96px}.ui-icon-unlocked{background-position:-208px -96px}.ui-icon-bookmark{background-position:-224px -96px}.ui-icon-tag{background-position:-240px -96px}.ui-icon-home{background-position:0 -112px}.ui-icon-flag{background-position:-16px -112px}.ui-icon-calendar{background-position:-32px -112px}.ui-icon-cart{background-position:-48px -112px}.ui-icon-pencil{background-position:-64px -112px}.ui-icon-clock{background-position:-80px -112px}.ui-icon-disk{background-position:-96px -112px}.ui-icon-calculator{background-position:-112px -112px}.ui-icon-zoomin{background-position:-128px -112px}.ui-icon-zoomout{background-position:-144px -112px}.ui-icon-search{background-position:-160px -112px}.ui-icon-wrench{background-position:-176px -112px}.ui-icon-gear{background-position:-192px -112px}.ui-icon-heart{background-position:-208px -112px}.ui-icon-star{background-position:-224px -112px}.ui-icon-link{background-position:-240px -112px}.ui-icon-cancel{background-position:0 -128px}.ui-icon-plus{background-position:-16px -128px}.ui-icon-plusthick{background-position:-32px -128px}.ui-icon-minus{background-position:-48px -128px}.ui-icon-minusthick{background-position:-64px -128px}.ui-icon-close{background-position:-80px -128px}.ui-icon-closethick{background-position:-96px -128px}.ui-icon-key{background-position:-112px -128px}.ui-icon-lightbulb{background-position:-128px -128px}.ui-icon-scissors{background-position:-144px -128px}.ui-icon-clipboard{background-position:-160px -128px}.ui-icon-copy{background-position:-176px -128px}.ui-icon-contact{background-position:-192px -128px}.ui-icon-image{background-position:-208px -128px}.ui-icon-video{background-position:-224px -128px}.ui-icon-script{background-position:-240px -128px}.ui-icon-alert{background-position:0 -144px}.ui-icon-info{background-position:-16px -144px}.ui-icon-notice{background-position:-32px -144px}.ui-icon-help{background-position:-48px -144px}.ui-icon-check{background-position:-64px -144px}.ui-icon-bullet{background-position:-80px -144px}.ui-icon-radio-on{background-position:-96px -144px}.ui-icon-radio-off{background-position:-112px -144px}.ui-icon-pin-w{background-position:-128px -144px}.ui-icon-pin-s{background-position:-144px -144px}.ui-icon-play{background-position:0 -160px}.ui-icon-pause{background-position:-16px -160px}.ui-icon-seek-next{background-position:-32px -160px}.ui-icon-seek-prev{background-position:-48px -160px}.ui-icon-seek-end{background-position:-64px -160px}.ui-icon-seek-start{background-position:-80px -160px}.ui-icon-seek-first{background-position:-80px -160px}.ui-icon-stop{background-position:-96px -160px}.ui-icon-eject{background-position:-112px -160px}.ui-icon-volume-off{background-position:-128px -160px}.ui-icon-volume-on{background-position:-144px -160px}.ui-icon-power{background-position:0 -176px}.ui-icon-signal-diag{background-position:-16px -176px}.ui-icon-signal{background-position:-32px -176px}.ui-icon-battery-0{background-position:-48px -176px}.ui-icon-battery-1{background-position:-64px -176px}.ui-icon-battery-2{background-position:-80px -176px}.ui-icon-battery-3{background-position:-96px -176px}.ui-icon-circle-plus{background-position:0 -192px}.ui-icon-circle-minus{background-position:-16px -192px}.ui-icon-circle-close{background-position:-32px -192px}.ui-icon-circle-triangle-e{background-position:-48px -192px}.ui-icon-circle-triangle-s{background-position:-64px -192px}.ui-icon-circle-triangle-w{background-position:-80px -192px}.ui-icon-circle-triangle-n{background-position:-96px -192px}.ui-icon-circle-arrow-e{background-position:-112px -192px}.ui-icon-circle-arrow-s{background-position:-128px -192px}.ui-icon-circle-arrow-w{background-position:-144px -192px}.ui-icon-circle-arrow-n{background-position:-160px -192px}.ui-icon-circle-zoomin{background-position:-176px -192px}.ui-icon-circle-zoomout{background-position:-192px -192px}.ui-icon-circle-check{background-position:-208px -192px}.ui-icon-circlesmall-plus{background-position:0 -208px}.ui-icon-circlesmall-minus{background-position:-16px -208px}.ui-icon-circlesmall-close{background-position:-32px -208px}.ui-icon-squaresmall-plus{background-position:-48px -208px}.ui-icon-squaresmall-minus{background-position:-64px -208px}.ui-icon-squaresmall-close{background-position:-80px -208px}.ui-icon-grip-dotted-vertical{background-position:0 -224px}.ui-icon-grip-dotted-horizontal{background-position:-16px -224px}.ui-icon-grip-solid-vertical{background-position:-32px -224px}.ui-icon-grip-solid-horizontal{background-position:-48px -224px}.ui-icon-gripsmall-diagonal-se{background-position:-64px -224px}.ui-icon-grip-diagonal-se{background-position:-80px -224px}.ui-corner-all,.ui-corner-top,.ui-corner-left,.ui-corner-tl{border-top-left-radius:3px}.ui-corner-all,.ui-corner-top,.ui-corner-right,.ui-corner-tr{border-top-right-radius:3px}.ui-corner-all,.ui-corner-bottom,.ui-corner-left,.ui-corner-bl{border-bottom-left-radius:3px}.ui-corner-all,.ui-corner-bottom,.ui-corner-right,.ui-corner-br{border-bottom-right-radius:3px}.ui-widget-overlay{background:#aaa;opacity:.003;filter:Alpha(Opacity=.3)}.ui-widget-shadow{-webkit-box-shadow:0 0 5px #666;box-shadow:0 0 5px #666} -------------------------------------------------------------------------------- /js/cal_options.js: -------------------------------------------------------------------------------- 1 | $(window).load(function(){ 2 | if(localStorage.getItem("calFixIntrinsic")=="true"){ 3 | $("#calOpFixIntrinsicCheck").prop( "checked", true ); 4 | }else{ 5 | $("#calOpFixIntrinsicCheck").prop( "checked", false ); 6 | } 7 | if(localStorage.getItem("calUseIntrinsic")=="true"){ 8 | $("#calOpUseIntrinsicCheck").prop( "checked", true ); 9 | }else{ 10 | $("#calOpUseIntrinsicCheck").prop( "checked", false ); 11 | } 12 | if(localStorage.getItem("calUseExtrinsic")=="true"){ 13 | $("#calOpUseExtrinsicCheck").prop( "checked", true ); 14 | }else{ 15 | $("#calOpUseExtrinsicCheck").prop( "checked", false ); 16 | } 17 | if(localStorage.getItem("calFixPrincipal")=="true"){ 18 | $("#calOpFixPrincipalCheck").prop( "checked", true ); 19 | }else{ 20 | $("#calOpFixPrincipalCheck").prop( "checked", false ); 21 | } 22 | if(localStorage.getItem("calFixAspect")=="true"){ 23 | $("#calOpFixAspectCheck").prop( "checked", true ); 24 | }else{ 25 | $("#calOpFixAspectCheck").prop( "checked", false ); 26 | } 27 | if(localStorage.getItem("calSameFocalLength")=="true"){ 28 | $("#calOpSameFocalCheck").prop( "checked", true ); 29 | }else{ 30 | $("#calOpCheckSameFocal").prop( "checked", false ); 31 | } 32 | if(localStorage.getItem("calZeroTangentDist")=="true"){ 33 | $("#calOpZeroTangentCheck").prop( "checked", true ); 34 | }else{ 35 | $("#calOpZeroTangentCheck").prop( "checked", false ); 36 | } 37 | if(localStorage.getItem("calFixK1")=="true"){ 38 | $("#calOpFixK1Check").prop( "checked", true ); 39 | }else{ 40 | $("#calOpFixK1Check").prop( "checked", false ); 41 | } 42 | if(localStorage.getItem("calFixK2")=="true"){ 43 | $("#calOpFixK2Check").prop( "checked", true ); 44 | }else{ 45 | $("#calOpFixK2Check").prop( "checked", false ); 46 | } 47 | if(localStorage.getItem("calFixK3")=="true"){ 48 | $("#calOpFixK3Check").prop( "checked", true ); 49 | }else{ 50 | $("#calOpFixK3Check").prop( "checked", false ); 51 | } 52 | }); 53 | 54 | 55 | 56 | $("#calOptionsDefaultsButton").on('click',function(){ 57 | $("#calOpFixIntrinsicCheck").prop( "checked", false ); 58 | $("#calOpUseIntrinsicCheck").prop( "checked", true ); 59 | $("#calOpUseExtrinsicCheck").prop( "checked", false ); 60 | $("#calOpFixPrincipalCheck").prop( "checked", false ); 61 | $("#calOpFixAspectCheck").prop( "checked", false ); 62 | $("#calOpSameFocalCheck").prop( "checked", false ); 63 | $("#calOpZeroTangentCheck").prop( "checked", true ); 64 | $("#calOpFixK1Check").prop( "checked", false ); 65 | $("#calOpFixK2Check").prop( "checked", false ); 66 | $("#calOpFixK3Check").prop( "checked", false ); 67 | }); 68 | 69 | 70 | $("#calOptionsApplyButton").on('click',function(){ 71 | calFixIntrinsic = "false"; 72 | calUseIntrinsic = "true"; 73 | calUseExtrinsic = "false"; 74 | calFixPrincipal = "false"; 75 | calFixAspect = "false"; 76 | calSameFocalLength = "false"; 77 | calZeroTangentDist = "true"; 78 | calFixK1 ="false"; 79 | calFixK2 = "false"; 80 | calFixK3 = "false"; 81 | if($("#calOpFixIntrinsicCheck")[0].checked){ 82 | localStorage.setItem("calFixIntrinsic","true"); 83 | }else{ 84 | localStorage.setItem("calFixIntrinsic","false"); 85 | } 86 | if($("#calOpUseIntrinsicCheck")[0].checked){ 87 | localStorage.setItem("calUseIntrinsic","true"); 88 | }else{ 89 | localStorage.setItem("calUseIntrinsic","false"); 90 | } 91 | if($("#calOpUseExtrinsicCheck")[0].checked){ 92 | localStorage.setItem("calUseExtrinsic","true"); 93 | }else{ 94 | localStorage.setItem("calUseExtrinsic","false"); 95 | } 96 | if($("#calOpFixPrincipalCheck")[0].checked){ 97 | localStorage.setItem("calFixPrincipal","true"); 98 | }else{ 99 | localStorage.setItem("calFixPrincipal","false"); 100 | } 101 | if($("#calOpFixAspectCheck")[0].checked){ 102 | localStorage.setItem("calFixAspect","true"); 103 | }else{ 104 | localStorage.setItem("calFixAspect","false"); 105 | } 106 | if($("#calOpSameFocalCheck")[0].checked){ 107 | localStorage.setItem("calSameFocalLength","true"); 108 | }else{ 109 | localStorage.setItem("calSameFocalLength","false"); 110 | } 111 | if($("#calOpZeroTangentCheck")[0].checked){ 112 | localStorage.setItem("calZeroTangentDist","true"); 113 | }else{ 114 | localStorage.setItem("calZeroTangentDist","false"); 115 | } 116 | if($("#calOpFixK1Check")[0].checked){ 117 | localStorage.setItem("calFixK1","true"); 118 | }else{ 119 | localStorage.setItem("calFixK1","false"); 120 | } 121 | if($("#calOpFixK2Check")[0].checked){ 122 | localStorage.setItem("calFixK2","true"); 123 | }else{ 124 | localStorage.setItem("calFixK2","false"); 125 | } 126 | if($("#calOpFixK3Check")[0].checked){ 127 | localStorage.setItem("calFixK3","true"); 128 | }else{ 129 | localStorage.setItem("calFixK3","false"); 130 | } 131 | window.close(); 132 | }); 133 | -------------------------------------------------------------------------------- /js/file_utils.js: -------------------------------------------------------------------------------- 1 | // 2 | 3 | function fullPath(folder,file){ 4 | if(typeof workingDirectory === 'undefined' || workingDirectory === null || workingDirectory == 'undefined'){ 5 | workingDirectory = localStorage.getItem("workingDirectory"); 6 | console.log('fullPath(): getting workingDirectory from local storage'); 7 | } 8 | var filePath = workingDirectory; 9 | if(folder!=''){ 10 | if(os.platform()=='win32'){ 11 | filePath += '\\' + folder; 12 | }else{ 13 | filePath += '/' + folder; 14 | } 15 | } 16 | if(os.platform()=='win32'){ 17 | filePath += '\\' + file; 18 | }else{ 19 | filePath += '/' + file; 20 | } 21 | //console.log('fullPath(): ',filePath); 22 | return filePath; 23 | } 24 | 25 | function autoDetectImageSequence(folderPath,cb){ 26 | fs.readdir(folderPath, (err,dir) => { 27 | if(!dir) return; 28 | 29 | // remove any hidden files from the dir list 30 | var i = dir.length; 31 | while (i--) { 32 | if(dir[i].charAt(0)==='.') 33 | dir.splice(i,1); 34 | } 35 | 36 | // only mono and stereo implemented at this point, no trinocular 37 | 38 | // supported image file naming patterns: 39 | // CASE A (stereo) leftPrefix_image# and rightPrefix_image# example left00034.jpeg and right00034.jpeg 40 | // CASE B (single camera) prefix_image# example cal-sys-a-00034.tif 41 | // CASE C (stereo) prefix_image#_leftSuffix and prefix_image#_rightSuffix example cal-sys-a-00034_0.tif and cal-sys-a-00034_1.tif 42 | // CASE D (single camera) prefix_image#_leftSuffix (no right files, this case is from using only the left images of a stetero naming convention) 43 | 44 | // note the prefix can be empty such as this CASE C example 00034_0.tif 00034_1.tif 45 | 46 | // split the filenames up into tokens to figure out the pattern 47 | var extension = ''; 48 | var delim = ''; 49 | imageTokens = []; 50 | for(var i = 0; i < dir.length; i++) { 51 | // skip any file that doesn't have an image file extension 52 | ext = dir[i].split('.').pop(); 53 | if(extension=='') 54 | if(ext=='tif'||ext=='TIF'||ext=='TIFF'||ext=='tiff'||ext=='JPG'||ext=='JPEG'||ext=='jpeg'||ext=='jpg'||ext=='png'||ext=='PNG'||ext=='bmp'||ext=='BMP') 55 | extension = ext; 56 | if(ext==extension){ // take the first image extension and skip any files that don't have this extension 57 | // split up the name into components: 58 | trimName = dir[i]; 59 | // remove the extension 60 | trimName = trimName.substr(0,trimName.length - ext.length - 1); // minus 1 to get rid of the dot 61 | //console.log('trim name: ' + trimName); 62 | // next grab the numbers at the end of the file name which either indicate the camera number or the frame number 63 | // if its not a number on the end return 64 | if(!$.isNumeric(trimName.slice(-1))) return; 65 | lastToken = trimName.split(/[\D]/).pop(); // delimiter is any non-number character 66 | //console.log('lastToken: ' + lastToken); 67 | preName = trimName.substr(0,trimName.length - lastToken.length) 68 | // remove an underscore or minus if it exists 69 | delim = ''; 70 | if(preName.slice(-1)=='-'){ 71 | delim = '-'; 72 | preName = preName.slice(0,-1); 73 | } 74 | if(preName.slice(-1)=='_'){ 75 | delim = '_'; 76 | preName = preName.slice(0,-1); 77 | } 78 | //console.log('preName: ' + preName); 79 | // what's left should either be a text prefix or a number or a prefix and number 80 | middleToken = preName.split(/[\D]/).pop(); // delimiter is any non-number character 81 | //console.log('middleToken: ' + middleToken); 82 | if(middleToken.length==0||middleToken.length==preName.length) // no number so its a prefix only, or number only so no prefix 83 | imageTokens.push([lastToken,preName]) 84 | else{ 85 | firstToken = preName.substr(0,preName.length - middleToken.length); 86 | imageTokens.push([lastToken,middleToken,firstToken]); 87 | } 88 | } 89 | } 90 | extension = '.' + extension; 91 | //console.log(imageTokens); 92 | 93 | // now figure out what the file naming pattern is: 94 | if(imageTokens.length<3) return; // needs at least three files found in this folder 95 | var prefix = ''; 96 | var startIndex = 0; 97 | var endIndex = 0; 98 | var numDigits = 0; 99 | var suffix = ''; 100 | var leftSuffix = ''; 101 | var rightSuffix = ''; 102 | var rightPrefix = ''; 103 | var leftPrefix = ''; 104 | var frameInterval = 1; 105 | // the last token should either be an image number or a camera number 106 | testLastToken = imageTokens[0][0]; 107 | numRepeats = 0; 108 | patternCase = 'A'; 109 | for(i=1;i1){ //not an image number, must be a suffix 114 | if(imageTokens[0].length == 2){ 115 | if(numRepeats==dir.length-1) 116 | patternCase = 'D'; 117 | else 118 | patternCase = 'C'; 119 | } 120 | else{ 121 | // could be case B with a number in the prefix so test for this 122 | testMiddleToken = imageTokens[0][1]; 123 | numMiddleRepeats = 0; 124 | for(i=1;i 1){ 129 | //console.log('I am case B with a number in the prefix'); 130 | patternCase = 'B'; 131 | }else{ 132 | if(numRepeats==dir.length-1) 133 | patternCase = 'D'; 134 | else 135 | patternCase = 'C'; 136 | } 137 | } 138 | } else { 139 | // if the prefixes are all the same it's case B, otherwise case A 140 | allPrefixesTheSame = true; 141 | testPrefix = imageTokens[0][imageTokens[0].length-1] 142 | for(i=1;i2){ // catch the case where there is a number in the prefix 166 | leftPrefix = firstRow[firstRow.length-1] + firstRow[firstRow.length-2] + delim; 167 | rightPrefix = lastRow[firstRow.length-1] + lastRow[lastRow.length-2] + delim; 168 | } 169 | break; 170 | case 'B': 171 | console.log('file naming convention case B'); 172 | prefix = firstRow[firstRow.length-1] + delim; 173 | if(firstRow.length>2) // catch the case where there is a number in the prefix 174 | prefix = firstRow[firstRow.length-1] + firstRow[firstRow.length-2] + delim; 175 | break; 176 | case 'C': 177 | console.log('file naming convention case C'); 178 | numberCol = 1; 179 | // prefix can be empty 180 | if(firstRow.length>2) // if there is no prefix the row length is 2 181 | prefix = firstRow[firstRow.length-1]; 182 | leftSuffix = delim + firstRow[0]; 183 | rightSuffix = delim + lastRow[0]; 184 | break; 185 | case 'D': 186 | console.log('file naming convention case D'); 187 | numberCol = 1; 188 | // prefix can be empty 189 | if(firstRow.length>2) // if there is no prefix the row length is 2 190 | prefix = firstRow[firstRow.length-1]; 191 | suffix = delim + firstRow[0]; 192 | break; 193 | default: 194 | //console.log('default case'); 195 | return; 196 | // code block 197 | } 198 | startIndex = Number(firstRow[numberCol]); 199 | endIndex = Number(lastRow[numberCol]); 200 | numDigits = lastRow[numberCol].length; 201 | if(patternCase=='C') 202 | frameInterval = Number(imageTokens[2][numberCol]) - Number(firstRow[numberCol]); 203 | else 204 | frameInterval = Number(secondRow[numberCol]) - Number(firstRow[numberCol]); 205 | 206 | console.log('auto file detection successful'); 207 | console.log('extension: ' + extension); 208 | console.log('delim: ' + delim); 209 | console.log('prefix: ' + prefix); 210 | console.log('startIndex: ' + startIndex); 211 | console.log('endIndex: ' + endIndex); 212 | console.log('numDigits: ' + numDigits); 213 | console.log('frameInt: ' + frameInterval); 214 | console.log('suffix: ' + suffix); 215 | console.log('leftSuffix: ' + leftSuffix); 216 | console.log('rightSuffix: ' + rightSuffix); 217 | console.log('leftPrefix: ' + leftPrefix); 218 | console.log('rightPrefix: ' + rightPrefix); 219 | 220 | var obj = { 221 | extension: extension, 222 | prefix: prefix, 223 | suffix: suffix, 224 | startIndex: startIndex, 225 | endIndex: endIndex, 226 | numDigits: numDigits, 227 | frameInterval: frameInterval, 228 | leftSuffix: leftSuffix, 229 | rightSuffix: rightSuffix, 230 | leftPrefix: leftPrefix, 231 | rightPrefix: rightPrefix 232 | }; 233 | cb(obj); 234 | }); 235 | } 236 | 237 | function deleteFileIfExists(fileName,cb){ 238 | cb = cb || $.noop; 239 | fs.readdir(workingDirectory, (err,dir) => { 240 | if(!dir)return; 241 | for(var i = 0; i < dir.length; i++) { 242 | (function(i) { 243 | filePath = dir[i]; 244 | if(filePath.includes(fileName)){ 245 | console.log('attempting to delete file ' + filePath); 246 | fullFilePath = fullPath('',filePath); 247 | fs.stat(fullFilePath, function(err, stat) { 248 | console.log('stat called on file ' + fullFilePath); 249 | if(err == null) { 250 | fs.unlink(fullFilePath, (err) => { 251 | if (err) throw err; 252 | console.log('successfully deleted '+fullFilePath); 253 | cb(); 254 | return; 255 | }); 256 | }else{ 257 | // no-op 258 | } 259 | }); // end stat 260 | } //end includes 261 | })(i); 262 | } // end dir loop 263 | cb(); // call the callback if the file wasn't found 264 | }); 265 | } 266 | 267 | 268 | -------------------------------------------------------------------------------- /js/global.js: -------------------------------------------------------------------------------- 1 | //const os = require('os'); 2 | 3 | // Global variables: 4 | 5 | // working directory 6 | var workingDirectory = "undefined"; 7 | var linux_path = ''; 8 | var darwin_path = '/Applications/DICe.app/Contents/Resources/app/bin/'; 9 | var win_path = 'C:\\Program Files (x86)\\Digital Image Correlation Engine\\'; 10 | 11 | var execPath; 12 | var execCrossInitPath; 13 | var execVideoStatPath; 14 | var execCalPath; 15 | var execOpenCVServerPath; 16 | var execTrackingMoviePath; 17 | var execEpilinePath; 18 | 19 | if(os.platform()=='win32'){ 20 | setExecPaths(win_path); 21 | }else if(os.platform()=='linux'){ 22 | setExecPaths(linux_path); 23 | }else if(os.platform()=='darwin'){ 24 | setExecPaths(darwin_path); 25 | } 26 | // the exec paths above can be overridden by setting a execPathOverride 27 | // valiable in .dice.js, if that variable exists the paths get 28 | // updated in utils.js 29 | 30 | // true if debugging messages are turned on for the dice executable 31 | var diceDebugMsgOn = false; 32 | var diceTrackLibOn = false; 33 | 34 | // image sets 35 | var refImagePathLeft = "undefined"; 36 | var refImagePathRight = "undefined"; 37 | var defImagePathsLeft = []; 38 | var defImagePathsRight = []; 39 | var videoPathLeft = "undefined"; 40 | var videoPathRight = "undefined"; 41 | var videoFirstFrame = 0; 42 | var calPath = "undefined"; 43 | 44 | // blocking subsets (used for legacy tracking code) 45 | var blockingSubsets = [[]]; 46 | var roiType = 'ROI'; 47 | 48 | // reference image dimensions 49 | var refImageWidth = 0; 50 | var refImageHeight = 0; 51 | 52 | // best fit plane locations 53 | var bestFitXOrigin = 0; 54 | var bestFitYOrigin = 0; 55 | var bestFitXAxis = 0; 56 | var bestFitYAxis = 0; 57 | 58 | // regions of interest 59 | var drawEpilineActive = false; 60 | 61 | // state of windows etc. in interface 62 | var showPrefPane = true; 63 | var showStereoPane = 0; 64 | var viewersStacked = false; 65 | var showConsole = true; 66 | //var paraviewMsg = true; 67 | 68 | // state of the results files 69 | var resultsFresh = false; 70 | 71 | function setExecPaths(path){ 72 | if(os.platform()=='win32'){ 73 | execPath = path + 'dice.exe'; 74 | execCrossInitPath = path + 'DICe_CrossInit.exe'; 75 | execVideoStatPath = path + 'DICe_VideoStat.exe'; 76 | execCalPath = path + 'DICe_Cal.exe'; 77 | execOpenCVServerPath = path + 'DICe_OpenCVServer.exe'; 78 | execEpilinePath = path + 'DICe_Epiline.exe'; 79 | execTrackingMoviePath = path + 'DICe_TrackingMovieMaker.exe'; 80 | }else if(os.platform()=='linux' || os.platform()=='darwin'){ 81 | execPath = path + 'dice'; 82 | execCrossInitPath = path + 'DICe_CrossInit'; 83 | execVideoStatPath = path + 'DICe_VideoStat'; 84 | execCalPath = path + 'DICe_Cal'; 85 | execOpenCVServerPath = path + 'DICe_OpenCVServer'; 86 | execEpilinePath = path + 'DICe_Epiline'; 87 | execTrackingMoviePath = path + 'DICe_TrackingMovieMaker'; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /js/live_plot.js: -------------------------------------------------------------------------------- 1 | var nIntervId; 2 | var firstPlot = true; 3 | var dataObjs = []; 4 | var currentTable = 0; 5 | 6 | function livePlotRepeat() { 7 | console.log('livePlotRepeat():'); 8 | var workingDir = localStorage.getItem("workingDirectory"); 9 | var fileNameStr = localStorage.getItem("livePlotFiles"); 10 | var fileNames = fileNameStr.split(/[ ,]+/); 11 | for(i=0;i'); 87 | var liID = "li_livePlot_" + currentTable; 88 | var firstValidIndex = getFirstValidIndex(dataObjs); 89 | var liTitle = dataObjs[firstValidIndex].headings[currentTable]; 90 | var layout = { 91 | xaxis: { 92 | title: { 93 | text: 'Frame', 94 | }, 95 | }, 96 | yaxis: { 97 | title: { 98 | text: liTitle, 99 | } 100 | }, 101 | margin: { 102 | l: 60, 103 | r: 50, 104 | b: 40, 105 | t: 10, 106 | pad: 4, 107 | }, 108 | }; 109 | var plotlyData = []; 110 | for(i=0;i { 66 | // check if the file matches the syntax 67 | if(file.indexOf('live_plot_line_frame_') !== -1){ 68 | // grab the index of the file 69 | var suffixAndExt = file.split("_").pop(); 70 | var suffix = suffixAndExt.substr(0, suffixAndExt.indexOf('.')); 71 | var stepID = Number(suffix); 72 | steps.push(stepID); 73 | if(stepID > latestLineFileIndex){ 74 | latestLineFileIndex = stepID; 75 | } 76 | } 77 | }); 78 | steps.sort(function(a, b){return a-b}); 79 | var selectOptions = []; 80 | for(i=0;i'+ steps[i] +''); 82 | $('#stepSelect').html(selectOptions.join('')); 83 | $('#stepSelect').val(currentStep); 84 | if(plottingPausedLine) return; 85 | if(currentStep!=latestLineFileIndex) 86 | $('#stepSelect').val(latestLineFileIndex); 87 | lineFile += 'live_plot_line_frame_' + latestLineFileIndex + '.txt'; 88 | console.log('live plot line file: ' + lineFile); 89 | plotLine(lineFile); 90 | } 91 | 92 | function plotLine(lineFile){ 93 | dataObjsLine = []; 94 | dataObjsLine.push({fileName:lineFile,roi_id:-1,headings:[],data:[],initialized:false}); 95 | var promise = fileToDataObj(dataObjsLine,0); // should only be one line plot file 96 | promise.then(function(response) { 97 | if(response[0]=="file read failed!"||response=="file read failed!"){ 98 | console.log('failed to load live_plot_line files'); 99 | return; 100 | } 101 | console.log("fileToDataObj succeeded!", response); 102 | if(firstPlotLine){ 103 | for(i=0;i'); 125 | var liID = "li_livePlotLine_" + currentTableLine; 126 | var liTitle = dataObjsLine[0].headings[currentTableLine]; 127 | 128 | var layout = { 129 | xaxis: { 130 | title: { 131 | text: 'Arc-length along line (px)', 132 | }, 133 | }, 134 | yaxis: { 135 | // autorange: 'true', 136 | // fixedrange: 'false', 137 | title: { 138 | text: liTitle, 139 | } 140 | }, 141 | margin: { 142 | l: 60, 143 | r: 50, 144 | b: 40, 145 | t: 10, 146 | pad: 4, 147 | }, 148 | }; 149 | // if($("#fixAxisCheck")[0].checked){ 150 | //// layout.yaxis.fixedrange = 'true'; 151 | // layout.yaxis.autorange = 'false'; 152 | // } 153 | var lineColor = plotlyDefaultColor(9); 154 | var plotlyData = {x:[],y:[],type:'scatter',line:{color:lineColor}}; 155 | plotlyData.x = dataObjsLine[0].data[0]; 156 | plotlyData.y = dataObjsLine[0].data[currentTableLine]; 157 | var config = { 158 | displaylogo: false, 159 | scrollZoom: true, 160 | responsive: true, 161 | modeBarButtonsToRemove: [ 162 | 'autoScale2d', 163 | 'select2d', 164 | 'lasso2d' 165 | ] 166 | }; 167 | Plotly.newPlot(document.getElementById(divID),[plotlyData],layout,config); 168 | } 169 | -------------------------------------------------------------------------------- /js/live_plot_tracklib.js: -------------------------------------------------------------------------------- 1 | function addTracklibFieldstoFieldSelect(cb){ 2 | $("#livePlotFieldSelect").empty(); 3 | $("#livePlotFieldSelect").append(new Option('world coord x (world dim)','x')); 4 | $("#livePlotFieldSelect").append(new Option('world coord y (world dim)','y')); 5 | $("#livePlotFieldSelect").append(new Option('world coord z (world dim)','z')); 6 | $("#livePlotFieldSelect").append(new Option('area (px)','area')); 7 | $("#livePlotFieldSelect").append(new Option('gray (counts)','gray')); 8 | $("#livePlotFieldSelect").append(new Option('Δx(world)/frame','velX')); 9 | $("#livePlotFieldSelect").append(new Option('Δy(world)/frame','velY')); 10 | $("#livePlotFieldSelect").append(new Option('Δz(world)/frame','velZ')); 11 | cb = cb || $.noop; 12 | cb(); 13 | } 14 | 15 | $("#trackGID").change(function() { 16 | if($('#trackGID').val()<0){ 17 | alert('invalid global id: ' + $("#trackGID").val()); 18 | $('#trackGID').val(0); 19 | } 20 | updateInspectors('left',-1); 21 | $("#trackDisplayModeSelect").trigger("change"); 22 | // updateTracklib2dScatter(); 23 | }); 24 | 25 | 26 | $("#trackGID").keypress(function(event) { 27 | if (event.keyCode === 13) { 28 | if($('#trackGID').val()<0){ 29 | alert('invalid global id: ' + $("#trackGID").val()); 30 | $('#trackGID').val(0); 31 | } 32 | updateInspectors('left',-1); 33 | // updateTracklib2dScatter(); 34 | } 35 | }); 36 | 37 | function updateTracklib2dScatter(){ 38 | var div = document.getElementById("livePlots"); 39 | var data = document.getElementById("livePlot3d").data; // grab the data that is stored on the 3d plot 40 | if(!data) return; 41 | var fieldText = $("#livePlotFieldSelect option:selected" ).text(); 42 | var field = $("#livePlotFieldSelect option:selected" ).val(); 43 | var id = parseInt($("#trackGID").val()); 44 | // pull the 2d information from the 3d scatter trace 45 | var traceName = "3dScatterTrace_" + id.toString(); 46 | var curveNum = data.findIndex(obj => { 47 | return obj.name === traceName; 48 | }); 49 | if(curveNum<0){ 50 | alert('invalid global id: ' + $("#trackGID").val()); 51 | $("#trackGID").val(0).change(); 52 | // purge the 2d results 53 | // Plotly.purge(document.getElementById("livePlots")); 54 | // updateTracklib2dScatter(); 55 | return; 56 | } 57 | if(!data[curveNum].hasOwnProperty(field)){ 58 | alert('error: invalid 2d field requested: ' + fieldText); 59 | return; 60 | } 61 | var layout = { 62 | xaxis: {title: {text: 'frame'}}, 63 | yaxis: {title: {text: fieldText}}, 64 | margin: {l:60,r:50,b:40,t:10,pad:4}, 65 | autosize: true, 66 | hovermode: 'closest', 67 | }; 68 | var config = { 69 | displaylogo: false, 70 | scrollZoom: true, 71 | responsive: true, 72 | modeBarButtonsToRemove: [ 73 | 'autoScale2d', 74 | 'select2d', 75 | 'lasso2d', 76 | 'hoverCompareCartesian', 77 | 'hoverClosestCartesian' 78 | ], 79 | }; 80 | var data2d = { 81 | name: '2dScatterTrace', 82 | hovertemplate : '(%{x},%{y})', 83 | visible: true, 84 | type:'scatter', 85 | mode:'lines+markers', 86 | showlegend: false, 87 | line: {color: '#316395', width: 2}, 88 | marker: {color: '#316395', size: 7}, 89 | x: data[curveNum].frame, 90 | y: data[curveNum][field], 91 | leftIndex: data[curveNum].leftIndex 92 | } 93 | Plotly.newPlot(div,[data2d],layout,config); 94 | div.on('plotly_click', function(data){ 95 | if(data.points[0].data.name==='2dScatterTrace'){ 96 | var index2d = data.points[0].data.leftIndex[data.points[0].pointIndex]; 97 | updateInspectors('left',index2d); 98 | } 99 | }); 100 | } 101 | 102 | function updateTracklib3dScatter(data,camera,cb){ 103 | var div = document.getElementById("livePlot3d"); 104 | // according to the docs, the camera position is not in terms of the data coordinate system 105 | // but some other frame of reference where the center is the "center of the 3d domain" (whatever that means) 106 | // the up vector needs to be flipped upside down because in DIC and computer vision Y is down 107 | // The z coodinate of the eye vector is set to -2 to try and view the whole field of view of results, 108 | // this might need to be adjusted later. 109 | var layout3d = { 110 | scene : { 111 | aspectmode: 'data', 112 | xaxis: { 113 | title: { 114 | text: 'world coord x', 115 | }, 116 | }, 117 | yaxis: { 118 | scaleanchor: 'x', 119 | title: { 120 | text: 'world coord y', 121 | } 122 | }, 123 | zaxis: { 124 | scaleanchor: 'x', 125 | title: { 126 | text: 'world coord z', 127 | } 128 | }, 129 | camera: { 130 | // center: camera.center, 131 | // eye: camera.eye, 132 | // up: camera.up, 133 | center: {x: 0, y: 0, z: 0}, 134 | eye: {x: 0, y: 0, z:-2.8}, 135 | up: {x: 0, y: -1, z: 0}, 136 | }, 137 | }, 138 | margin: { 139 | l: 0, 140 | r: 0, 141 | b: 0, 142 | t: 0, 143 | pad: 4, 144 | } 145 | }; 146 | var config = { 147 | displaylogo: false, 148 | scrollZoom: true, 149 | responsive: true, 150 | modeBarButtonsToRemove: [ 151 | 'hoverCompareCartesian', 152 | 'hoverClosestCartesian', 153 | ], 154 | }; 155 | // TODO add configuration 156 | Plotly.newPlot(div,data,layout3d,config); 157 | cb = cb || $.noop; 158 | cb(); 159 | 160 | div.on('plotly_click', function(data){ 161 | // console.log(data); 162 | // NOTE: in 3d trace the point id is pointNumber not pointIndex like it is for 2d 163 | if(data.points[0].data.name.includes('3dScatterTrace_')){ 164 | var ptNum = data.points[0].pointNumber; 165 | var leftIndex = data.points[0].data.leftIndex[ptNum]; 166 | updateInspectors('left',leftIndex);//,data.points[0].curveNumber,ptNum); 167 | } 168 | }); 169 | } 170 | 171 | function highlightTrack(curveNum,ptIndex){ 172 | // color all the trace lines back to the default 173 | var update = { 174 | 'marker.color': '#FB00D1', 175 | 'marker.size' : 4, 176 | 'line.color': '#FB00D1', 177 | 'line.width': 2 178 | }; 179 | setTimeout(function(){ 180 | Plotly.restyle("livePlot3d", update); 181 | // color the trace for this point 182 | if(ptIndex<0||curveNum<0){ 183 | // turn off any selected points 184 | var div3d = document.getElementById("livePlot3d"); 185 | var traceId3d = div3d.data.findIndex(obj => { 186 | return obj.name === "selected3dPoint"; 187 | }); 188 | if(traceId3d>=0) 189 | Plotly.deleteTraces(div3d,traceId3d); 190 | var div2d = document.getElementById("livePlots"); 191 | var traceId2d = div2d.data.findIndex(obj => { 192 | return obj.name === "selected2dPoint"; 193 | }); 194 | if(traceId2d>=0) 195 | Plotly.deleteTraces(div2d,traceId2d); 196 | } 197 | update = { 198 | 'marker.color': '#316395', 199 | 'line.color': '#316395', 200 | 'line.width': 4 201 | } 202 | if(curveNum>=0){ 203 | Plotly.restyle("livePlot3d", update,curveNum); 204 | if(ptIndex>=0){ 205 | addClickedPointTrace(curveNum,ptIndex); 206 | addClickedPointTrace2d(curveNum,ptIndex); 207 | } 208 | } 209 | },200); // BUG in Plotly requires this timeout 210 | } 211 | 212 | function addClickedPointTrace(curveNum,ptIndex){ 213 | var div = document.getElementById("livePlot3d"); 214 | var x = [div.data[curveNum].x[ptIndex]]; 215 | var y = [div.data[curveNum].y[ptIndex]]; 216 | var z = [div.data[curveNum].z[ptIndex]]; 217 | var text = [div.data[curveNum].text[ptIndex]]; 218 | var traceId = div.data.findIndex(obj => { 219 | return obj.name === "selected3dPoint"; 220 | }); 221 | if(traceId<0){ 222 | var trace = { 223 | name: 'selected3dPoint', 224 | hovertemplate : '(%{x},%{y},%{z})
%{text}', 225 | visible: true, 226 | type:'scatter3d', 227 | x:x, 228 | y:y, 229 | z:z, 230 | text: text, 231 | mode:'markers', 232 | showlegend: false, 233 | marker: {color: '#316395', size: 8}, 234 | }; 235 | Plotly.addTraces(div,trace); 236 | }else{ 237 | var update = {x:[x],y:[y],z:[z],text:[text],visible:true,marker: {color: '#316395', size: 8}}; 238 | Plotly.restyle(div,update,traceId); 239 | } 240 | } 241 | 242 | function addClickedPointTrace2d(curveNum,ptIndex){ 243 | if($('#trackGID').val()!=curveNum){ 244 | $('#trackGID').val(curveNum);//.change(); 245 | updateTracklib2dScatter(); 246 | } 247 | 248 | var div = document.getElementById("livePlots"); 249 | if(!div.data) return; 250 | if(ptIndex<0||ptIndex>=div.data[0].x.length) return; 251 | var x = [div.data[0].x[ptIndex]]; 252 | var y = [div.data[0].y[ptIndex]]; 253 | var traceId = div.data.findIndex(obj => { 254 | return obj.name === "selected2dPoint"; 255 | }); 256 | if(traceId<0){ 257 | var trace = { 258 | name: 'selected2dPoint', 259 | visible: true, 260 | type:'scatter', 261 | x:x, 262 | y:y, 263 | mode:'markers', 264 | showlegend: false, 265 | marker: {color: '#316395', size: 14}, 266 | hovertemplate : '(%{x},%{y})', 267 | }; 268 | Plotly.addTraces(div,trace); 269 | }else{ 270 | var update = {x:[x],y:[y],visible:true,marker: {color: '#316395', size: 14}}; 271 | Plotly.restyle(div,update,traceId); 272 | } 273 | } 274 | 275 | function setTrackingVisibility(){ 276 | var dataVisible = $('#showTrackingCheck')[0].checked || isResultsMode(); 277 | var linesVisible = ($('#showTrackingCheck')[0].checked && $("#numPreviewFrames").val()>1) || isResultsMode(); 278 | if(linesVisible){ 279 | $(".track-plot").show(); 280 | } 281 | else { 282 | $(".track-plot").hide(); 283 | } 284 | var update = {visible:dataVisible}; 285 | var pvl = document.getElementById("plotlyViewerLeft"); 286 | var pvr = document.getElementById("plotlyViewerRight"); 287 | if(pvl.data){ 288 | var ids = []; 289 | for(var i=0;i { 315 | return obj.name === "tracklibPreviewScatter"; 316 | }); 317 | if(scatterTraceId<0) return; 318 | var stereoGlobalId = 0; 319 | if(index2d<0) stereoGlobalId = Number($("#trackGID").val()); 320 | else{ // get the stereo GID from the clicked point data 321 | if(!data[scatterTraceId].frame) return; 322 | var frame = data[scatterTraceId].frame[index2d]; 323 | if(!data[scatterTraceId].stereoGlobalId) return; 324 | stereoGlobalId = data[scatterTraceId].stereoGlobalId[index2d]; 325 | if(stereoGlobalId<0) return; 326 | } 327 | // detemine the 3d index based on the frame # 328 | var traceName = "3dScatterTrace_" + stereoGlobalId.toString(); 329 | var curveNum = -1; 330 | var index3d = -1; 331 | var data3d = document.getElementById("livePlot3d").data; 332 | if(!data3d) return; 333 | curveNum = data3d.findIndex(obj => { 334 | return obj.name === traceName; 335 | }); 336 | if(curveNum<0){ 337 | alert('invalid global id: ' + $("#trackGID").val()); 338 | curveNum = 0; 339 | $("#trackGID").val(curveNum); 340 | } 341 | // if(curveNum<0)return; 342 | if(index2d>0){ 343 | for(var i=0;i { 496 | // return obj.name === "tracklibPreviewScatter"; 497 | // }); 498 | // if(scatterTraceId<0) return; 499 | // var px = data[scatterTraceId].x; 500 | // var py = data[scatterTraceId].y; 501 | // var fwdNeighId = data[scatterTraceId].fwdNeighId; 502 | // // draw lines between all the points that have neighbors 503 | // // remove all old track_lines 504 | // if(!layout.shapes) layout.shapes = []; 505 | // var i = layout.shapes.length; 506 | // while (i--) { 507 | // if(layout.shapes[i].name) 508 | // if(layout.shapes[i].name==='trackLine') 509 | // layout.shapes.splice(i,1); 510 | // } 511 | // for(var i=0;i=1){ 78 | //console.log('prevLine ' + prevLine); 79 | dataObjs[fileIt].headings = prevLine; 80 | //obj.headings = resDataLines[i-1].split(/[ ,]+/); 81 | } 82 | i--; 83 | } 84 | prevLine = thisLineSplit; 85 | } 86 | dataObjs[fileIt].initialized = true; 87 | console.log('file read was successful ' + file); 88 | dataObjs[fileIt].data = transpose(dataObjs[fileIt].data); 89 | // obj.data.map((_, colIndex) => obj.data.map(row => row[colIndex])); 90 | // console.log(obj); 91 | // dataObjs.push(obj); 92 | resolve('file read success!'); 93 | }); 94 | }// end null 95 | else{ // always resolve ... 96 | // dataObjs.push(obj); 97 | console.log('file read failed ' + file); 98 | console.log(err); 99 | resolve('file read failed!'); 100 | //reject('file read failure!'); 101 | } 102 | }); // end stat 103 | }); 104 | } -------------------------------------------------------------------------------- /js/parser.js: -------------------------------------------------------------------------------- 1 | 2 | function parse_input_xml_file(filename){ 3 | console.log("parsing input file " + filename); 4 | fs.stat(filename, function(err, stat) { 5 | if(err == null) { 6 | $.ajax({ 7 | type: "GET", 8 | url: filename, 9 | dataType: "xml", 10 | success: function(xml) { 11 | impl_input_xml_file(xml); 12 | }, // end success 13 | }); // end ajax 14 | }else{ // file doesn't exist 15 | } 16 | }); // end stat 17 | } 18 | 19 | 20 | function parseSubsetFile(xml){ 21 | // read the subset file if it exists: 22 | // check if a subset file is used to define ROIs 23 | subset_file = xml_get(xml,"subset_file"); 24 | if(subset_file){ 25 | console.log('reading subset file: ' + subset_file); 26 | fs.stat(subset_file, function(err, stat) { 27 | if(err == null) { 28 | fs.readFile(subset_file,'utf8',function(err,data){ 29 | if(err){ 30 | }else{ 31 | readSubsetFile(data); 32 | } 33 | }); // end readfile 34 | }else{ // file doesn't exist 35 | readLivePlotFile(); 36 | readBestFitFile(); 37 | checkContourJsonFileExists(); 38 | } 39 | }); // end stat subset file 40 | } // end has subset_file 41 | else{ 42 | readLivePlotFile(); 43 | readBestFitFile(); 44 | checkContourJsonFileExists(); 45 | } 46 | } 47 | 48 | function impl_input_xml_file(xml){ 49 | 50 | is_subset_or_global = false; 51 | 52 | // set the step size 53 | step_size = xml_get(xml,"step_size"); 54 | console.log('step_size: ' + step_size); 55 | if(step_size){ 56 | $("#stepSize").val(step_size); 57 | $("#stepSizeLabel").text(step_size); 58 | } 59 | // set the subset size 60 | subset_size = xml_get(xml,"subset_size"); 61 | console.log('subset_size: ' + subset_size); 62 | if(subset_size){ 63 | $("#subsetSize").val(subset_size); 64 | $("#subsetSizeLabel").text(subset_size); 65 | drawRepresentativeSubset(); 66 | } 67 | if(step_size || subset_size){ 68 | is_subset_or_global = true; 69 | // override the method if there is a step size or subset size 70 | $("#analysisModeSelect").val("subset").change(); 71 | } 72 | 73 | // set the mesh size 74 | mesh_size = xml_get(xml,"mesh_size"); 75 | console.log('mesh_size: ' + mesh_size); 76 | if(mesh_size){ 77 | $("#meshSize").val(mesh_size); 78 | $("#meshSizeLabel").text(mesh_size); 79 | } 80 | if(mesh_size){ 81 | is_subset_or_global = true; 82 | // override the method if there is a step size or subset size 83 | $("#analysisModeSelect").val("global").change(); 84 | } 85 | 86 | if(!is_subset_or_global){ 87 | // override the method if there is a step size or subset size 88 | $("#analysisModeSelect").val("tracking").change(); 89 | } 90 | 91 | // no text output files produced 92 | noText = xml_get(xml,"no_text_output_files"); 93 | if(noText == "true"){ 94 | $("#omitTextCheck")[0].checked = true; 95 | } 96 | 97 | // read the images (one of three options 1: sequence of images, 2: video file, or 3: list of images 98 | image_folder = xml_get(xml,"image_folder"); 99 | // video 100 | video_file = xml_get(xml,"cine_file"); 101 | if(!video_file) video_file = xml_get(xml,"video_file"); 102 | if(video_file){ 103 | console.log('reading video file: ' + image_folder + video_file); 104 | $("#fileSelectMode").val("video"); 105 | stereo_video_file = xml_get(xml,"stereo_cine_file"); 106 | if(!stereo_video_file) stereo_video_file = xml_get(xml,"stereo_video_file"); 107 | if(stereo_video_file){ 108 | showStereoViewer(); 109 | } 110 | else show2DViewer(); 111 | $("#fileSelectMode").change(); 112 | full_name = image_folder + video_file; 113 | callVideoStatExec(full_name,0,function(){update_video_indices(xml); parseSubsetFile(xml);}); 114 | if(stereo_video_file){ 115 | console.log('reading stereo video file: ' + image_folder + stereo_video_file); 116 | stereo_full_name = image_folder + stereo_video_file; 117 | callVideoStatExec(stereo_full_name,1); 118 | } 119 | }else{ 120 | // list 121 | ref_image = xml_get(xml,"reference_image"); 122 | if(ref_image){ 123 | console.log('reading reference image: ' + image_folder + ref_image); 124 | $("#fileSelectMode").val("list"); 125 | $("#fileSelectMode").change(); 126 | stereo_ref_image = xml_get(xml,"stereo_reference_image"); 127 | if(stereo_ref_image) showStereoViewer(); 128 | else show2DViewer(); 129 | // load the ref image 130 | full_name = image_folder + ref_image; 131 | name_splits = full_name.split(/[\\\/]/); 132 | $("#refImageText span").text(name_splits[name_splits.length-1]); 133 | updatePreviewImage({srcPath:full_name,dest:'left'},function(){parseSubsetFile(xml); refImagePathLeft = full_name;}); 134 | // load the deformed image list 135 | deformed_list = $(xml).find('ParameterList[name="deformed_images"]'); 136 | if(deformed_list){ 137 | $("#defImageListLeft").empty(); 138 | defImagePathsLeft = []; 139 | $(deformed_list).find('Parameter').each(function(){ 140 | full_def_name = image_folder + $(this).attr('name'); 141 | console.log('deformed image left: ' + full_def_name); 142 | def_name_split = full_def_name.split(/[\\\/]/); 143 | current_length_li = $("#defImageListLeft").size(); 144 | $("#defImageListLeft").append("
  • " + def_name_split[def_name_split.length-1] + "
  • "); 145 | getFileObject(full_def_name, function (fileObject) { 146 | defImagePathsLeft.push(fileObject); 147 | updateFrameScrollerRange(); 148 | // sort the defImagePathsLeft in case the asynch getFileObject re-ordered the list 149 | defImagePathsLeft.sort(function(a, b) { 150 | return (a.name > b.name) - (a.name < b.name); 151 | }); 152 | }); 153 | }); 154 | } 155 | // load the stereo ref image 156 | if(stereo_ref_image){ 157 | stereo_full_name = image_folder + stereo_ref_image; 158 | stereo_name_splits = stereo_full_name.split(/[\\\/]/); 159 | $("#refImageTextRight span").text(stereo_name_splits[stereo_name_splits.length-1]); 160 | updatePreviewImage({srcPath:stereo_full_name,dest:'right'},function(){refImagePathRight = stereo_full_name;}); 161 | } 162 | // load the stereo deformed image list 163 | stereo_deformed_list = $(xml).find('ParameterList[name="stereo_deformed_images"]'); 164 | if(stereo_deformed_list){ 165 | $("#defImageListRight").empty(); 166 | defImagePathsRight = []; 167 | $(stereo_deformed_list).find('Parameter').each(function(){ 168 | full_def_name = image_folder + $(this).attr('name'); 169 | console.log('deformed image right: ' + full_def_name); 170 | def_name_split = full_def_name.split(/[\\\/]/); 171 | current_length_li = $("#defImageListRight").size(); 172 | $("#defImageListRight").append("
  • " + def_name_split[def_name_split.length-1] + "
  • "); 173 | getFileObject(full_def_name, function (fileObject) { 174 | defImagePathsRight.push(fileObject); 175 | // sort the defImagePathsRight in case the asynch getFileObject re-ordered the list 176 | defImagePathsRight.sort(function(a, b) { 177 | return (a.name > b.name) - (a.name < b.name); 178 | }); 179 | }); 180 | }); 181 | } 182 | } 183 | // sequence 184 | else{ 185 | console.log('image folder for sequence: ' + image_folder); 186 | $("#fileSelectMode").val("sequence"); 187 | $("#fileSelectMode").change(); 188 | $("#imageFolderSpan").text(image_folder); 189 | stereo_right_suffix = xml_get(xml,"stereo_right_suffix"); 190 | if(stereo_right_suffix) showStereoViewer(); 191 | else show2DViewer(); 192 | ref_image_index = xml_get(xml,"reference_image_index"); 193 | console.log('ref image index: ' + ref_image_index); 194 | if(ref_image_index) $("#refIndex").val(ref_image_index); 195 | end_image_index = xml_get(xml,"end_image_index"); 196 | console.log('last image index: ' + end_image_index); 197 | if(end_image_index) $("#endIndex").val(end_image_index); 198 | start_image_index = xml_get(xml,"start_image_index"); 199 | console.log('start image inde: ' + start_image_index); 200 | if(start_image_index) $("#startIndex").val(start_image_index); 201 | skip_image_index = xml_get(xml,"skip_image_index"); 202 | console.log('skip image index: ' + skip_image_index); 203 | if(skip_image_index) $("#skipIndex").val(skip_image_index); 204 | stereo_left_suffix = xml_get(xml,"stereo_left_suffix"); 205 | console.log('strereo left suffix: ' + stereo_left_suffix); 206 | if(stereo_left_suffix) $("#stereoLeftSuffix").val(stereo_left_suffix); 207 | console.log('stereo right suffix: ' + stereo_right_suffix); 208 | if(stereo_right_suffix) $("#stereoRightSuffix").val(stereo_right_suffix); 209 | num_digits = xml_get(xml,"num_file_suffix_digits"); 210 | if(num_digits) $("#numDigits").val(num_digits); 211 | image_prefix = xml_get(xml,"image_file_prefix"); 212 | if(image_prefix) $("#imagePrefix").val(image_prefix); 213 | image_suffix = xml_get(xml,"file_suffix"); 214 | if(image_suffix) $("#imageSuffix").val(image_suffix); 215 | image_ext = xml_get(xml,"image_file_extension"); 216 | if(image_ext) $("#imageExtension").val(image_ext); 217 | updateFrameScrollerRange(); 218 | loadImageSequence(function(){parseSubsetFile(xml);}); 219 | } 220 | } 221 | 222 | // see if there is a calibration parameters file 223 | calPath = xml_get(xml,"camera_system_file"); 224 | console.log('has calibration file: ' + calPath); 225 | if(calPath && calPath !== 'null' && calPath != 'undefined'){ 226 | $("#calList").empty(); 227 | // pull off the file name from the above path 228 | //substrs = calPath.split(/[\\\/]/); 229 | //console.log(substrs); 230 | var calFileName = calPath.split(/[\\\/]/).pop(); 231 | //console.log('cal file name is ' + calFileName); 232 | $("#calList").append("
  • " + calFileName + "
  • "); 233 | } 234 | 235 | // see if there is a parameters file 236 | paramsFile = xml_get(xml,"correlation_parameters_file"); 237 | if(paramsFile){ 238 | parse_params_xml_file(paramsFile); 239 | } 240 | checkValidInput(); 241 | } 242 | 243 | function readBestFitFile(){ 244 | // see if there is a "best_fit_plane.dat" file in the folder 245 | var bestFitFileName = fullPath('','best_fit_plane.dat'); 246 | var ox = 0; 247 | var oy = 0; 248 | var px = 0; 249 | var py = 0; 250 | fs.stat(bestFitFileName, function(err, stat) { 251 | if(err == null) { 252 | fs.readFile(bestFitFileName,'utf8',function(err,data){ 253 | if(err){ 254 | }else{ 255 | //var pre_coord_data = data.toString().split(/\s+/g).map(Number); 256 | var lines = data.toString().split('\n'); 257 | var coord_data = []; 258 | for(var line = 0; line < lines.length; line++){ 259 | if(lines[line].charAt(0)=='#') continue; 260 | var tokens = lines[line].split(/\s+/g).map(Number); 261 | for(var i=0;i 0){ 423 | hierarchy.pop(); 424 | } 425 | } // end split_line 426 | } // end lines 427 | //console.log(blockingSubsets); 428 | // assuming here that the plotly div already exists 429 | var update = {shapes: shapes}; 430 | Plotly.relayout(document.getElementById("plotlyViewerLeft"),update); 431 | if(subsetLocations.x.length>0){ 432 | var scatterTrace = { 433 | name: 'subsetCoordinates', 434 | visible: false, 435 | type:'scatter', 436 | x:subsetLocations.x, 437 | y:subsetLocations.y, 438 | hovertemplate : '(%{x},%{y})', 439 | mode:'markers', 440 | marker: { 441 | color: 'yellow', 442 | size: 3 443 | }, 444 | }; 445 | Plotly.addTraces(document.getElementById("plotlyViewerLeft"),scatterTrace); 446 | } 447 | readLivePlotFile(); 448 | readBestFitFile(); 449 | checkContourJsonFileExists(); 450 | } 451 | 452 | function update_video_indices(xml){ 453 | video_start_index = xml_get(xml,"cine_start_index"); 454 | if(!video_start_index) video_start_index = xml_get(xml,"video_start_index"); 455 | if(video_start_index && video_start_index!='undefined') {$("#videoStartIndex").val(video_start_index);} 456 | video_end_index = xml_get(xml,"cine_end_index"); 457 | if(!video_end_index) video_end_index = xml_get(xml,"video_end_index"); 458 | if(video_end_index && video_end_index!='undefined') {$("#videoEndIndex").val(video_end_index);} 459 | video_skip_index = xml_get(xml,"cine_skip_index"); 460 | if(!video_skip_index) video_skip_index = xml_get(xml,"video_skip_index"); 461 | if(video_skip_index && video_skip_index!='undefined') {$("#videoSkipIndex").val(video_skip_index);} 462 | video_ref_index = xml_get(xml,"cine_ref_index"); 463 | if(!video_ref_index) video_ref_index = xml_get(xml,"video_ref_index"); 464 | if(video_ref_index && video_ref_index!='undefined') {$("#videoRefIndex").val(video_ref_index);} 465 | $("#frameScroller").val(video_ref_index); 466 | $("#currentPreviewSpan").text(video_ref_index); 467 | } 468 | 469 | function parse_params_xml_file(filename){ 470 | console.log("parsing correlation parameters file " + filename); 471 | $.ajax({ 472 | type: "GET", 473 | url: filename, 474 | dataType: "xml", 475 | success: function(xml) { 476 | impl_params_xml_file(xml); 477 | } // end success 478 | }); // end ajax 479 | } 480 | 481 | function impl_params_xml_file(xml){ 482 | // set the initialization method 483 | init_method = xml_get(xml,"initialization_method"); 484 | console.log('init_method: ' + init_method); 485 | if(init_method=="USE_FEATURE_MATCHING"){ 486 | $("#initSelect").val("featureMatching"); 487 | } 488 | if(init_method=="USE_FIELD_VALUES"){ 489 | $("#initSelect").val("fieldValues"); 490 | } 491 | if(init_method=="USE_NEIGHBOR_VALUES"){ 492 | $("#initSelect").val("neighborValues"); 493 | } 494 | if(init_method=="USE_IMAGE_REGISTRATION"){ 495 | $("#initSelect").val("imageRegistration"); 496 | } 497 | // set the sssig threshold 498 | sssig = xml_get(xml,"sssig_threshold"); 499 | console.log('sssig_threshold: ' + sssig); 500 | if(sssig && sssig!='undefined'){ 501 | $("#sssigThresh").val(sssig); 502 | $("#sssigLabel").text(sssig); 503 | } 504 | // set the shape functions 505 | trans = xml_get(xml,"enable_translation"); 506 | console.log('enable translation: ' + trans); 507 | if(trans == "true"){ 508 | $("#translationCheck")[0].checked = true; 509 | }else{ 510 | $("#translationCheck")[0].checked = false; 511 | } 512 | rotation = xml_get(xml,"enable_rotation"); 513 | console.log('enable rotation: ' + rotation); 514 | if(rotation == "true"){ 515 | $("#rotationCheck")[0].checked = true; 516 | }else{ 517 | $("#rotationCheck")[0].checked = false; 518 | } 519 | normal = xml_get(xml,"enable_normal_strain"); 520 | console.log('enable normal: ' + normal); 521 | if(normal == "true"){ 522 | $("#normalStrainCheck")[0].checked = true; 523 | }else{ 524 | $("#normalStrainCheck")[0].checked = false; 525 | } 526 | shear = xml_get(xml,"enable_shear_strain"); 527 | console.log('enable shear: ' + shear); 528 | if(shear == "true"){ 529 | $("#shearStrainCheck")[0].checked = true; 530 | }else{ 531 | $("#shearStrainCheck")[0].checked = false; 532 | } 533 | // gauss filtering of images 534 | filter = xml_get(xml,"gauss_filter_images"); 535 | console.log('gauss filtering: ' + filter); 536 | if(filter == "true"){ 537 | $("#filterCheck")[0].checked = true; 538 | filter_size = xml_get(xml,"gauss_filter_mask_size"); 539 | console.log('gauss filter mask size ' + filter_size); 540 | if(filter_size){ 541 | $("#filterSize").val(filter_size); 542 | $("#filterSizeLabel").text(filter_size); 543 | } 544 | } 545 | // vsg strain 546 | vsg_strain = $(xml).find('ParameterList[name="post_process_vsg_strain"]').find('Parameter[name="strain_window_size_in_pixels"]').attr("value"); 547 | console.log('vsg strain window size: ' + vsg_strain); 548 | if(vsg_strain){ 549 | $("#strainCheck")[0].checked = true; 550 | $("#strainGaugeSize").val(vsg_strain); 551 | $("#strainGaugeSizeLabel").text(vsg_strain); 552 | }else{ 553 | $("#strainCheck")[0].checked = false; 554 | } 555 | // global parameters 556 | reg_constant = xml_get(xml,"global_regularization_alpha"); 557 | console.log('global regularization alpha ' + reg_constant); 558 | if(reg_constant){ 559 | $("#regularizationConstant").val(reg_constant); 560 | $("#regularizationConstantLabel").text(reg_constant); 561 | } 562 | threshold_method = xml_get(xml,"threshold_method"); 563 | console.log('threhsold_method: ' + threshold_method); 564 | if(threshold_method=="guildenbecher"){ 565 | $("#thresholdModeSelect").val("guildenbecher").change(); 566 | } 567 | if(threshold_method=="threshold"){ 568 | $("#thresholdModeSelect").val("threshold").change(); 569 | } 570 | 571 | // tracking parameters 572 | min_thresh_left = xml_get(xml,"min_thresh_left"); 573 | console.log('min_thresh_left: ' + min_thresh_left); 574 | if(min_thresh_left) 575 | $("#minThreshLeft").val(min_thresh_left); 576 | max_thresh_left = xml_get(xml,"max_thresh_left"); 577 | console.log('max_thresh_left: ' + max_thresh_left); 578 | if(max_thresh_left) 579 | $("#maxThreshLeft").val(max_thresh_left); 580 | steps_thresh_left = xml_get(xml,"steps_thresh_left"); 581 | console.log('steps_thresh_left: ' + steps_thresh_left); 582 | if(steps_thresh_left) 583 | $("#stepsThreshLeft").val(steps_thresh_left); 584 | min_thresh_right = xml_get(xml,"min_thresh_right"); 585 | console.log('min_thresh_right: ' + min_thresh_right); 586 | if(min_thresh_right) 587 | $("#minThreshRight").val(min_thresh_right); 588 | max_thresh_right = xml_get(xml,"max_thresh_right"); 589 | console.log('max_thresh_right: ' + max_thresh_right); 590 | if(max_thresh_right) 591 | $("#maxThreshRight").val(max_thresh_right); 592 | steps_thresh_right = xml_get(xml,"steps_thresh_right"); 593 | console.log('steps_thresh_right: ' + steps_thresh_right); 594 | if(steps_thresh_right) 595 | $("#stepsThreshRight").val(steps_thresh_right); 596 | max_pt_density = xml_get(xml,"max_pt_density"); 597 | console.log('max_pt_density: ' + max_pt_density); 598 | if(max_pt_density) 599 | $("#maxPtDensity").val(max_pt_density); 600 | min_area = xml_get(xml,"min_area"); 601 | console.log('min_area: ' + min_area); 602 | if(min_area) 603 | $("#minArea").val(min_area); 604 | max_area = xml_get(xml,"max_area"); 605 | console.log('max_area: ' + max_area); 606 | if(max_area) 607 | $("#maxArea").val(max_area); 608 | colocation_tol = xml_get(xml,"colocation_tol"); 609 | console.log('colocation_tol: ' + colocation_tol); 610 | if(colocation_tol) 611 | $("#colocationTol").val(colocation_tol); 612 | neighbor_radius = xml_get(xml,"neighbor_radius"); 613 | console.log('neighbor_radius: ' + neighbor_radius); 614 | if(neighbor_radius) 615 | $("#neighborRadius").val(neighbor_radius); 616 | min_pts_per_track = xml_get(xml,"min_pts_per_track"); 617 | console.log('min_pts_per_track: ' + min_pts_per_track); 618 | if(min_pts_per_track) 619 | $("#minPtsPerTrack").val(min_pts_per_track); 620 | num_search_frames = xml_get(xml,"num_search_frames"); 621 | console.log('num_search_frames: ' + num_search_frames); 622 | if(num_search_frames) 623 | $("#numSearchFrames").val(num_search_frames); 624 | num_background = xml_get(xml,"num_background_frames"); 625 | console.log('num_background_frames: ' + num_background); 626 | if(num_background) 627 | $("#numBackgroundFrames").val(num_background); 628 | 629 | stereo_area_tol = xml_get(xml,"stereo_area_tol"); 630 | console.log('stereo_area_tol: ' + stereo_area_tol); 631 | if(stereo_area_tol) 632 | $("#stereoAreaTol").val(stereo_area_tol); 633 | 634 | stereo_area_weight = xml_get(xml,"stereo_area_weight"); 635 | console.log('stereo_area_weight: ' + stereo_area_weight); 636 | if(stereo_area_weight) 637 | $("#stereoAreaWeight").val(stereo_area_weight); 638 | 639 | dist_from_epi_tol = xml_get(xml,"dist_from_epi_tol"); 640 | console.log('dist_from_epi_tol: ' + dist_from_epi_tol); 641 | if(dist_from_epi_tol) 642 | $("#distFromEpiTol").val(dist_from_epi_tol); 643 | 644 | dist_from_epi_weight = xml_get(xml,"dist_from_epi_weight"); 645 | console.log('dist_from_epi_weight: ' + dist_from_epi_weight); 646 | if(dist_from_epi_weight) 647 | $("#distFromEpiWeight").val(dist_from_epi_weight); 648 | 649 | dist_weight = xml_get(xml,"dist_weight"); 650 | console.log('dist_weight: ' + dist_weight); 651 | if(dist_weight) 652 | $("#distWeight").val(dist_weight); 653 | 654 | area_tol = xml_get(xml,"area_tol"); 655 | console.log('area_tol: ' + area_tol); 656 | if(area_tol) 657 | $("#areaTol").val(area_tol); 658 | 659 | area_weight = xml_get(xml,"area_weight"); 660 | console.log('area_weight: ' + area_weight); 661 | if(area_weight) 662 | $("#areaWeight").val(area_weight); 663 | 664 | gray_tol = xml_get(xml,"gray_tol"); 665 | console.log('gray_tol: ' + gray_tol); 666 | if(gray_tol) 667 | $("#grayTol").val(gray_tol); 668 | 669 | gray_weight = xml_get(xml,"gray_weight"); 670 | console.log('gray_weight: ' + gray_weight); 671 | if(gray_weight) 672 | $("#grayWeight").val(gray_weight); 673 | 674 | angle_tol = xml_get(xml,"angle_tol"); 675 | console.log('angle_tol: ' + angle_tol); 676 | if(angle_tol) 677 | $("#angleTol").val(angle_tol); 678 | 679 | angle_weight = xml_get(xml,"angle_weight"); 680 | console.log('angle_weight: ' + angle_weight); 681 | if(angle_weight) 682 | $("#angleWeight").val(angle_weight); 683 | 684 | checkValidInput(); 685 | checkHasOutput(); 686 | } 687 | 688 | function xml_get(xml,param_name){ 689 | return $(xml).find('Parameter[name="'+param_name+'"]').attr("value"); 690 | } 691 | 692 | function cloneShape(shape){ 693 | var newShape = {}; 694 | newShape.type = shape.type; 695 | newShape.path = shape.path; 696 | newShape.line = {color: shape.line.color, width: shape.line.width}; 697 | newShape.fillcolor = shape.fillcolor; 698 | newShape.opacity = shape.opacity; 699 | newShape.editable = shape.editable; 700 | newShape.name = shape.name; 701 | return newShape; 702 | } 703 | 704 | function shapesToCentroids(shapes){ 705 | var centroids = {x:[],y:[]}; 706 | if(shapes.length==0) return; 707 | // iterate the shapes and for each path shape, compute the centroid 708 | for(var i=0;i { 51 | // // es5 52 | // // count up the number of potential files to delete 53 | // var numExistingFiles = 0; 54 | // if(!dir)return; 55 | // for(var i = 0; i < dir.length; i++) { 56 | // if(dir[i].includes(nameToCheck)) 57 | // numExistingFiles++; 58 | // } 59 | // console.log(numExistingFiles + ' display image files exist'); 60 | // if(numExistingFiles==0){ 61 | // cb(); 62 | // return; 63 | // } 64 | // for(var i = 0; i < dir.length; i++) { 65 | // (function(i) { 66 | // var filePath = dir[i]; 67 | // if(filePath.includes(nameToCheck)){ 68 | // console.log('attempting to delete file ' + filePath); 69 | // var fullFilePath = fullPath('.dice',filePath); 70 | // fs.stat(fullFilePath, function(err, stat) { 71 | // console.log('stat called on file ' + fullFilePath); 72 | // if(err == null) { 73 | // fs.unlink(fullFilePath, (err) => { 74 | // numExistingFiles--; 75 | // if (err) {}//throw err;} 76 | // else{ 77 | // console.log('successfully deleted '+fullFilePath+' '+i); 78 | // if(numExistingFiles==0) { 79 | // cb(); 80 | // } 81 | // } 82 | // }); 83 | // }else{ 84 | // // no-op 85 | // } 86 | // }); // end stat 87 | // } //end includes 88 | // })(i); 89 | // } 90 | // }); 91 | //} 92 | 93 | function deleteHiddenFiles(find_str,cb){ 94 | var cbCalled = false; 95 | cb = cb || $.noop; 96 | hiddenDir = fullPath('.dice',''); 97 | console.log('removing hidden files that include ' + find_str + ' from ' + hiddenDir); 98 | fs.readdir(hiddenDir, (err,dir) => { 99 | // count up the number of potential files to delete 100 | var numExistingFiles = 0; 101 | if(!dir)return; 102 | for(var i = 0; i < dir.length; i++) { 103 | if(dir[i].includes(find_str)) 104 | numExistingFiles++; 105 | } 106 | console.log(numExistingFiles + ' hidden files exist'); 107 | if(numExistingFiles==0){ 108 | cb(); 109 | return; 110 | } 111 | for(var i = 0; i < dir.length; i++) { 112 | (function(i) { 113 | var filePath = dir[i]; 114 | if(filePath.includes(find_str)){ 115 | console.log('attempting to delete file ' + filePath); 116 | var fullFilePath = fullPath('.dice',filePath); 117 | fs.stat(fullFilePath, function(err, stat) { 118 | console.log('stat called on file ' + fullFilePath); 119 | if(err == null) { 120 | fs.unlink(fullFilePath, (err) => { 121 | numExistingFiles--; 122 | if (err) {} // don't complain about the file not existing 123 | else{ 124 | console.log('successfully deleted '+fullFilePath+' '+i); 125 | if(numExistingFiles==0) { 126 | cb(); 127 | } 128 | } 129 | }); 130 | }else{ 131 | // no-op 132 | } 133 | }); // end stat 134 | } //end includes 135 | })(i); 136 | } 137 | }); 138 | } 139 | 140 | function copyFile(source, target, cb) { 141 | console.log('copying ' + source + ' to ' + target); 142 | var cbCalled = false; 143 | cb = cb || $.noop; 144 | var rd = fs.createReadStream(source); 145 | rd.on("error", function(err) { 146 | done(err); 147 | }); 148 | var wr = fs.createWriteStream(target); 149 | wr.on("error", function(err) { 150 | done(err); 151 | }); 152 | wr.on("close", function(ex) { 153 | done(); 154 | }); 155 | rd.pipe(wr); 156 | function done(err) { 157 | if (!cbCalled) { 158 | cb(err); 159 | cbCalled = true; 160 | } 161 | } 162 | } 163 | 164 | function flagSequenceImages(){ 165 | refImagePathLeft = "sequence"; 166 | refImagePathRight = "sequence"; 167 | defImagePathsLeft = ["sequence"]; 168 | defImagePathsRight = ["sequence"]; 169 | } 170 | 171 | function loadImageSequence(cb){ 172 | cb = cb || $.noop; 173 | var fullImageName = concatImageSequenceName(0); 174 | var fullStereoImageName = concatImageSequenceName(1); 175 | updateImageSequencePreview(); 176 | args = []; 177 | if($("#brightnessCheck")[0].checked){ 178 | args.push("filter:brightness"); 179 | args.push("brightness"); 180 | args.push($("#brightnessBeta").val()); 181 | } // true for tracklib 182 | if($("#equalizeHistCheck")[0].checked||($("#analysisModeSelect").val()=="tracking"&&showStereoPane==1)){ 183 | args.push("filter:equalize_hist"); 184 | } 185 | fs.stat(fullImageName, function(err, stat) { 186 | if(err != null) { 187 | alert("Invalid image file name: " + fullImageName); 188 | return; 189 | } 190 | else{ 191 | updatePreviewImage({srcPath:fullImageName,dest:'left'},cb); 192 | if(showStereoPane==1||showStereoPane==2){ 193 | fs.stat(fullStereoImageName, function(err, stat) { 194 | if(err != null) { 195 | alert("Invalid stereo image file name: " + fullStereoImageName); 196 | return; 197 | } 198 | updatePreviewImage({argsIn:args,srcPath:fullStereoImageName,dest:'right'}); 199 | flagSequenceImages(); 200 | }); 201 | } 202 | else{ 203 | flagSequenceImages(); 204 | } 205 | } 206 | }); 207 | } 208 | 209 | $("#consoleButton").on("click",function () { 210 | if(!$(this).hasClass('action-li')) return; 211 | $("#plotsButton").addClass('action-li'); 212 | $("#plotsButton").addClass('toggle-title'); 213 | $(this).removeClass('action-li'); 214 | $(this).addClass('toggle-title-bold'); 215 | $("#consoleWindow").show(); 216 | $("#plotsWindow").hide(); 217 | }); 218 | 219 | $("#plotsButton").on("click",function () { 220 | if(!$(this).hasClass('action-li')) return; 221 | $("#consoleButton").addClass('action-li'); 222 | $("#consoleButton").addClass('toggle-title'); 223 | $(this).removeClass('action-li'); 224 | $(this).addClass('toggle-title-bold'); 225 | $("#consoleWindow").hide(); 226 | $("#plotsWindow").show(); 227 | }); 228 | 229 | function isResultsMode(){ 230 | return !$("#resultsButton").hasClass('action-li'); 231 | } 232 | 233 | $("#resultsButton").on("click",function () { 234 | // check to see if there are any results files available 235 | if(!$(this).hasClass('action-li')) return; 236 | var resultsFile = '.dice/.results_left.json'; 237 | fs.stat(fullPath('',resultsFile), function(err, stat) { 238 | if(err == null) { 239 | $("#previewButton").addClass('action-li'); 240 | $("#previewButton").addClass('toggle-title'); 241 | $(this).removeClass('action-li'); 242 | $(this).addClass('toggle-title-bold'); 243 | $("#previewWindow :input").attr("disabled", true); 244 | $(".tracklib-preview-only").hide(); 245 | $("#resultsWindow").show(); 246 | // reload the results file 247 | $("#showTrackingCheck").prop("checked",true); 248 | reloadVideoImages($("#frameScroller").val()); 249 | }} 250 | ); 251 | }); 252 | 253 | $("#previewButton").on("click",function () { 254 | if(!$(this).hasClass('action-li')) return; 255 | $("#resultsButton").addClass('action-li'); 256 | $("#resultsButton").addClass('toggle-title'); 257 | $(this).removeClass('action-li'); 258 | $(this).addClass('toggle-title-bold'); 259 | $("#previewWindow :input").attr("disabled", false); 260 | $(".tracklib-preview-only").show(); 261 | $("#resultsWindow").hide(); 262 | $('#trackGID').val(0); 263 | reloadVideoImages($("#frameScroller").val()); 264 | }); 265 | 266 | 267 | //$("#loadSubsetFileInput").on("click",function () { 268 | // this.value = null; 269 | //}); 270 | 271 | $("#loadSubsetFileInput").change(function (evt) { 272 | if (confirm('Importing a subset locations file will reset all ROIs. Continue loading?')) { 273 | var tgt = evt.target || window.event.srcElement, 274 | file = tgt.files[0]; 275 | if(file){ 276 | fs.readFile(file.path,'utf8',function(err,data){ 277 | if(err){ 278 | }else{ 279 | readSubsetFile(data); 280 | $(this).prop("value", ""); 281 | removeSubsetPreview(); 282 | } 283 | }); // end readfile 284 | } 285 | }else{ 286 | $(this).prop("value", ""); 287 | return false; 288 | } 289 | }); 290 | 291 | //$("#loadRef").click(function (){ 292 | // loadImageSequence(); 293 | //}); 294 | 295 | $("#leftVideoInput").on("click",function () { 296 | this.value = null; 297 | }); 298 | $("#leftVideoInput").change(function (evt) { 299 | var tgt = evt.target || window.event.srcElement, 300 | file = tgt.files[0]; 301 | if(file){ 302 | // TODO if a right video file is alread loaded ask the user if it should be unloaded to 303 | // to avoid frame range mismatch 304 | // if(videoPathRight!="undefined"){ 305 | // if (confirm('unload right video file (this is necessary if the frame ranges are different between right and left video)')){ 306 | // deleteDisplayImageFiles(0); 307 | // deleteDisplayImageFiles(1); 308 | // deleteDisplayImageFiles(2); 309 | // deleteHiddenFiles('background'); 310 | // videoPathRight = "undefined"; 311 | // $("#videoRightPreviewSpan").text(""); 312 | // $("#startPreviewSpan").text(""); 313 | // $("#endPreviewSpan").text(""); 314 | // // create a tiff image of the selected reference frame 315 | // callVideoStatExec(file,0); 316 | // } 317 | // else{ 318 | // } 319 | // } // end a right video file exists 320 | // else{ 321 | callVideoStatExec(file.path,0); 322 | // } 323 | } 324 | }); 325 | 326 | $("#rightVideoInput").on("click",function () { 327 | this.value = null; 328 | }); 329 | $("#rightVideoInput").change(function (evt) { 330 | var tgt = evt.target || window.event.srcElement, 331 | file = tgt.files[0]; 332 | if(file){ 333 | // create a tiff image of the selected reference frame 334 | callVideoStatExec(file.path,1); 335 | } 336 | }); 337 | 338 | function reloadVideoImages(index,loadData=true){ 339 | // check that the ref index is valid 340 | if(videoPathLeft!="undefined"||videoPathRight!="undefined") 341 | if(index < Number($("#startPreviewSpan").text()) || index > Number($("#endPreviewSpan").text())){ 342 | alert("invalid index"); 343 | return; 344 | } 345 | var offsetIndex = Number(index); 346 | // for tracklib special filters can be applied over the images 347 | if($("#analysisModeSelect").val()=="tracking"&&showStereoPane==1&&($("#showSegmentationCheck")[0].checked||$("#showTrackingCheck")[0].checked)){ // signifies tracklib 348 | updateTracklibDisplayImages(offsetIndex,loadData); 349 | return; 350 | }else if($("#analysisModeSelect").val()=="tracking"&&showStereoPane==1){ // otherwise just diplay the raw frame 351 | // remove any plots or display lines 352 | resetPlotlyViewer('left'); 353 | resetPlotlyViewer('right'); 354 | Plotly.purge(document.getElementById("livePlots")); 355 | Plotly.purge(document.getElementById("livePlot3d")); 356 | if(videoPathLeft!="undefined") 357 | updateVideoDisplayImage(videoPathLeft,offsetIndex,'left',function(){showDeformedROIs();}); 358 | if(videoPathRight!="undefined") 359 | updateVideoDisplayImage(videoPathRight,offsetIndex,'right'); 360 | } 361 | if(videoPathLeft!="undefined") 362 | updateVideoDisplayImage(videoPathLeft,offsetIndex,'left',function(){showDeformedROIs();}); 363 | if(videoPathRight!="undefined") 364 | updateVideoDisplayImage(videoPathRight,offsetIndex,'right'); 365 | } 366 | 367 | 368 | // reload the left and right video image if the ref index is changed 369 | $("#videoRefIndex").change(function () { 370 | var refIndex = $("#videoRefIndex").val(); 371 | }); 372 | 373 | function selectHasValue(select, value) { 374 | obj = document.getElementById(select); 375 | if (obj !== null) { 376 | return (obj.innerHTML.indexOf('value="' + value + '"') > -1); 377 | } else { 378 | return false; 379 | } 380 | } 381 | 382 | function setScrollerText(val){ 383 | if($("#fileSelectMode").val()=="list" && val<0) 384 | $("#currentPreviewSpan").text('ref'); 385 | else 386 | $("#currentPreviewSpan").text(val); 387 | } 388 | 389 | $("#frameScroller").on('input', function () { 390 | setScrollerText($(this).val()); 391 | }).change(function(){ 392 | $("#warningLeft").text(""); 393 | $("#warningRight").text(""); 394 | setScrollerText($(this).val()); // call this again in case the value was set by a call to .val() which wouldn't fire the input event 395 | if($("#fileSelectMode").val()=="list"){ 396 | $('#defImageListLeft li').each(function(i){ 397 | $(this).removeClass('def-image-ul-selected'); 398 | }); 399 | $('#defImageListRight li').each(function(i){ 400 | $(this).removeClass('def-image-ul-selected'); 401 | }); 402 | args = []; 403 | if($("#brightnessCheck")[0].checked){ 404 | args.push("filter:brightness"); 405 | args.push("brightness"); 406 | args.push($("#brightnessBeta").val()); 407 | } // true by default for tracklib 408 | if($("#equalizeHistCheck")[0].checked||($("#analysisModeSelect").val()=="tracking"&&showStereoPane==1)){ 409 | args.push("filter:equalize_hist"); 410 | } 411 | if(Number($(this).val())<0){ 412 | if(refImagePathLeft!="") 413 | updatePreviewImage({argsIn:args,srcPath:refImagePathLeft,dest:'left'}); 414 | else{ 415 | resetPlotlyViewer('left'); 416 | } 417 | if(showStereoPane==1&&refImagePathRight!="") 418 | updatePreviewImage({argsIn:args,srcPath:refImagePathRight,dest:'right'}); 419 | else{ 420 | resetPlotlyViewer('right'); 421 | } 422 | }else{ 423 | var index = $(this).val(); 424 | if(defImagePathsLeft.length > $(this).val()){ 425 | updatePreviewImage({argsIn:args,srcPath:defImagePathsLeft[index].path,dest:'left'}); 426 | $("#defImageListLeft li:eq(" + index.toString() + ")").addClass("def-image-ul-selected"); 427 | } 428 | else{ 429 | resetPlotlyViewer('left'); 430 | } 431 | if(defImagePathsRight.length > $(this).val()){ 432 | updatePreviewImage({argsIn:args,srcPath:defImagePathsRight[index].path,dest:'right'}); 433 | $("#defImageListRight li:eq(" + index.toString() + ")").addClass("def-image-ul-selected"); 434 | } 435 | else{ 436 | resetPlotlyViewer('right'); 437 | } 438 | } 439 | }else if($("#fileSelectMode").val()=="sequence"){ 440 | updateImageSequencePreview(true); 441 | }else if($("#fileSelectMode").val()=="video"){ 442 | reloadVideoImages($(this).val(),!isResultsMode()); 443 | } 444 | if($("#analysisModeSelect").val()=="subset"||$("#analysisModeSelect").val()=="global"){ 445 | checkContourJsonFileExists(); 446 | } 447 | // turn off live plot info if this is not the first frame 448 | toggleLivePlotVisibility($(this).val()==$(this).attr('min')); 449 | if(selectHasValue("stepSelect",$(this).val())){ 450 | console.log('updating step select with val ' + $(this).val()); 451 | $("#stepSelect").val($(this).val()).change(); 452 | }else{ 453 | console.log('not updating step select since ' + $(this).val() + ' is not a valid option'); 454 | } 455 | showDeformedROIs(); 456 | removeSubsetPreview(); 457 | $("#trackDisplayModeSelect").trigger("change"); 458 | }); 459 | 460 | $("#videoGoToIndex").keypress(function(event) { 461 | if (event.keyCode === 13) { 462 | if($(this).val() < Number($("#startPreviewSpan").text()) || $(this).val() > Number($("#endPreviewSpan").text())){ 463 | alert("invalid index"); 464 | return; 465 | } 466 | $("#frameScroller").val($(this).val()); 467 | $("#currentPreviewSpan").text($(this).val()); 468 | reloadVideoImages($(this).val()); 469 | } 470 | }); 471 | 472 | $(".update-tracklib-preview").keypress(function(event) { 473 | if (event.keyCode === 13) { 474 | reloadVideoImages($("#frameScroller").val()); 475 | } 476 | }); 477 | 478 | $("#previewTracklib").on("click",function () { 479 | reloadVideoImages($("#frameScroller").val()); 480 | }); 481 | 482 | $("#rightRefInput").on("click",function () { 483 | this.value = null; 484 | }); 485 | $("#rightRefInput").change(function (evt) { 486 | var tgt = evt.target || window.event.srcElement, 487 | file = tgt.files[0]; 488 | $("#refImageTextRight span").text(file.name); 489 | updatePreviewImage({srcPath:file.path,dest:'right'},function(){refImagePathRight = file.path;}); 490 | updateFrameScrollerRange(); 491 | }); 492 | 493 | $("#calInput").on("click",function () { 494 | this.value = null; 495 | }); 496 | $("#calInput").change(function (evt) { 497 | var tgt = evt.target || window.event.srcElement, 498 | file = tgt.files[0]; 499 | if(file){ 500 | $("#calList").empty(); 501 | calPath = file.path; 502 | $("#calList").append("
  • " + file.name + "
  • "); 503 | checkValidInput(); 504 | } 505 | }); 506 | 507 | $("#calInfo").click(function(){ 508 | var arg1 = 900; 509 | var arg2 = 500; 510 | var arg3 = 'file://' + __dirname + '/cal_help.html'; 511 | //console.log(arg3) 512 | var args = {arg1, arg2, arg3} 513 | ipcRenderer.send('create-window',args); 514 | }); 515 | 516 | $("#leftRefInput").on("click",function () { 517 | this.value = null; 518 | }); 519 | $("#leftRefInput").change(function (evt) { 520 | var tgt = evt.target || window.event.srcElement, 521 | file = tgt.files[0]; 522 | $("#refImageText span").text(file.name); 523 | updatePreviewImage({srcPath:file.path,dest:'left'},function(){refImagePathLeft = file.path;}); 524 | }); 525 | 526 | $("#leftDefInput").on("click",function () { 527 | this.value = null; 528 | }); 529 | $("#leftDefInput").change(function (evt) { 530 | var tgt = evt.target || window.event.srcElement, 531 | files = tgt.files; 532 | if(files){ 533 | $("#defImageListLeft").empty(); 534 | defImagePathsLeft = []; 535 | for(var i = 0, l = files.length; i < l; i++) { 536 | var filePath = files[i].path; 537 | var fileName = files[i].name; 538 | $("#defImageListLeft").append("
  • " + fileName + "
  • "); 539 | defImagePathsLeft.push(files[i]);//filePath); 540 | } 541 | } 542 | checkValidInput(); 543 | updateFrameScrollerRange(); 544 | }); 545 | 546 | function createCalPreview(event){ 547 | // create an absolute position div and add it to the body 548 | div = $("
    ") 549 | div.html(''); 550 | div.attr({id: 'previewCalDiv', class: 'preview'}); 551 | var closeButton = $('