} /* DefineThumbnailGridViewRowAndColumns */

        private void  AddToThumbNailPanel()
        {
            if (images == null)
            {
                return;
            }

            int numCols = ThumbnailDataGridView.Columns.Count;

            thumbnailCurRow = ThumbnailDataGridView.Rows.Count - 1;
            if (ThumbnailDataGridView.Rows.Count == 0)
            {
                thumbnailCurCol = numCols;
            }

            int idx = 0;

            while (idx < images.Count)
            {
                PicesDataBaseImage i = images[idx];

                if (thumbnailCurCol >= numCols)
                {
                    object[] row = new object[numCols];
                    ThumbnailDataGridView.Rows.Add(row);
                    thumbnailCurRow = ThumbnailDataGridView.Rows.Count - 1;
                    thumbnailCurCol = 0;
                    ThumbnailDataGridView.Rows[thumbnailCurRow].Height = thumbNailHeight + 2;
                }

                ThumbnailDataGridView.Rows[thumbnailCurRow].Cells[thumbnailCurCol].Value = i;
                thumbnailCurCol++;
                idx++;
            }
        } /* AddToThumbNailPanel */
Beispiel #2
0
        } /* SaveImagesByDepthImcrements */

        private void  SaveImagesByClass()
        {
            images.Sort(PicesDataBaseImageList.SortOrderType.soClassName, false);

            int idx = 0;
            PicesDataBaseImage i = images[0];

            while ((idx < images.Count) && (!cancelRequested))
            {
                String className    = i.Class1Name;
                String curClassName = className;

                curDir = OSservices.AddSlash(DestinationDirectory.Text) + className;

                try { Directory.CreateDirectory(curDir); }  catch (Exception)  {}

                PicesDataBaseImageList imagesThisClass = new PicesDataBaseImageList();

                while ((idx < images.Count) && (!cancelRequested) && (className == curClassName))
                {
                    imagesThisClass.Add(i);
                    idx++;
                    if (idx < images.Count)
                    {
                        i         = images[idx];
                        className = i.Class1Name;
                    }
                }

                SaveImagesInList(imagesThisClass, curDir);
            }
        } /* SaveImagesByClass */
Beispiel #3
0
        } /* DeriveRandomDistByDepth */

        private PicesDataBaseImageList  GetDatabaseImageRecords(PicesDataBase threadConn,
                                                                List <ImageEntry> images
                                                                )
        {
            RunLogAddMsg("Extracting Images from the database." + "\n");
            PicesDataBaseImageList dataBaseImages = new PicesDataBaseImageList();

            foreach (ImageEntry ie  in  images)
            {
                if (cancelHarvesting)
                {
                    break;
                }

                PicesDataBaseImage dbi = threadConn.ImageLoad(ie.imageId);
                if (dbi == null)
                {
                    RunLogAddMsg("GetDatabaseImageRecords   ***ERROR***   Could not get ImageId[" + ie.imageId + "]" + "\n");
                }
                else
                {
                    dataBaseImages.Add(dbi);
                    if ((dataBaseImages.Count % 100) == 0)
                    {
                        RunLogAddMsg("Images Extracted " + dataBaseImages.Count + " of " + images.Count + "\n");
                    }
                }
            }

            return(dataBaseImages);
        } /* GetDatabaseImageRecords */
        public PredictionBreakDownDisplay(PicesDataBase _dbConn,
                                          PicesDataBaseImage _image,
                                          PicesRaster _raster,
                                          TrainingModel2 _trainingModel,
                                          PicesInstrumentData _instrumentData, /*!<  Instrument data that goes with image, if null will read from database. */
                                          PicesRunLog _runLog
                                          )
        {
            if (_runLog == null)
            {
                runLog = new PicesRunLog();
            }
            else
            {
                runLog = _runLog;
            }

            if (_image == null)
            {
                return;
            }

            fileName       = _image.ImageFileName;
            instrumentData = _instrumentData;
            trainingModel  = _trainingModel;

            PicesRaster raster = _raster;

            if (_dbConn != null)
            {
                if (raster == null)
                {
                    raster = _dbConn.ImageFullSizeFind(fileName);
                }

                if (instrumentData == null)
                {
                    instrumentData = _dbConn.InstrumentDataGetByScanLine(_image.SipperFileName, _image.TopLeftRow);
                }

                dbFeatureVector = _dbConn.FeatureDataRecLoad(fileName);
            }

            if (raster == null)
            {
                return;
            }

            //raster = raster.ConnectedComponent ();

            featureCalcImages = new PicesRasterList();
            featureVector     = new PicesFeatureVector(raster, fileName, featureCalcImages, runLog);
            if (instrumentData != null)
            {
                featureVector.AddInstrumentData(instrumentData);
            }

            InitializeComponent();
        }
Beispiel #5
0
        private PicesPredictionList  PredictClasses(PicesFeatureVector fv,
                                                    PicesPrediction pred1,
                                                    PicesPrediction pred2,
                                                    String imageFileName,
                                                    String imageFileRootName
                                                    )
        {
            PicesFeatureVector  fvToUse      = fv;
            PicesPredictionList probPredList = null;

            if (fvToUse.FeatureDataMissing)
            {
                fvToUse = null;

                // Feature data is missing.  we need to compute from original image.
                PicesDataBaseImage pdbi = DbConn().ImageLoad(imageFileRootName);
                if (pdbi != null)
                {
                    PicesRaster pr = DbConn().ImageFullSizeFind(imageFileRootName);
                    if (pr == null)
                    {
                        ErrorMsgsAdd("Failed to Load FullSize image [" + imageFileRootName + "]");
                    }
                    else
                    {
                        fvToUse = new PicesFeatureVector(pr, imageFileName, null, runLog);
                        // Since we had to compute the FeatureDatya from the raster image we now need to
                        // get the instrument data that matches it.
                        PicesInstrumentData id = DbConn().InstrumentDataGetByScanLine(pdbi.SipperFileName, pdbi.TopLeftRow);
                        if (id != null)
                        {
                            fvToUse.AddInstrumentData(id);
                        }
                        DbConn().FeatureDataInsertRow(pdbi.SipperFileName, fvToUse);
                        pr.Dispose();
                    }

                    pr = null;
                }
            }

            if (fvToUse != null)
            {
                classifier.PredictClass(fvToUse, pred1, pred2);
                probPredList = classifier.PredictProbabilities(fvToUse);
            }
            else
            {
                pred1.MLClass = PicesClassList.GetUnKnownClassStatic();   pred1.Probability = 1.0f;
                pred2.MLClass = PicesClassList.GetUnKnownClassStatic();   pred2.Probability = 0.0f;
            }

            return(probPredList);
        } /* PredictClasses */
        public PredictionBreakDownDisplayDual(PicesDataBase _dbConn,
                                              String _fileName,
                                              TrainingModel2 _trainingModel,
                                              PicesInstrumentData _instrumentData, /**<  Instrument data that goes with image,  if null will read from dtabase. */
                                              PicesRunLog _runLog
                                              )
        {
            if (_runLog == null)
            {
                runLog = new PicesRunLog();
            }
            else
            {
                runLog = _runLog;
            }

            fileName       = _fileName;
            instrumentData = _instrumentData;
            trainingModel  = _trainingModel;

            PicesDataBase dbConn = PicesDataBase.GetGlobalDatabaseManagerNewInstance(runLog);
            PicesRaster   raster = dbConn.ImageFullSizeFind(fileName);

            if (raster == null)
            {
                return;
            }

            if (_dbConn != null)
            {
                dbFeatureVector = _dbConn.FeatureDataRecLoad(_fileName);
                if (instrumentData == null)
                {
                    PicesDataBaseImage image = dbConn.ImageLoad(fileName);
                    if (image != null)
                    {
                        instrumentData = dbConn.InstrumentDataGetByScanLine(image.SipperFileName, image.TopLeftRow);
                    }
                }
            }

            featureVector = new PicesFeatureVector(raster, fileName, null, runLog);

            if (instrumentData != null)
            {
                featureVector.AddInstrumentData(instrumentData);
            }

            dbConn.Close();
            dbConn = null;
            GC.Collect();

            InitializeComponent();
        }
Beispiel #7
0
        private void  ViewImage(Object sender, EventArgs e)
        {
            String             imageFileName = lastSelectedImage;
            PicesDataBaseImage pi            = dbConn.ImageLoad(imageFileName);

            if (pi != null)
            {
                PicesRaster pr = dbConn.ImageFullSizeFind(imageFileName);
                ImageViewer iv = new ImageViewer(pr, pi, null);
                iv.ShowDialog(this);
            }
        }
Beispiel #8
0
        private void  CopyImageToClipboard(Object sender, EventArgs e)
        {
            String imageFileName = lastSelectedImage;

            PicesDataBaseImage pi = dbConn.ImageLoad(imageFileName);

            if (pi != null)
            {
                PicesRaster pr = dbConn.ImageFullSizeFind(imageFileName);
                Image       i  = pr.BuildBitmap();
                if (i != null)
                {
                    Clipboard.SetImage(i);
                }
            }
        } /* CopyImageToClipboard */
        } /* ProcessDirectory */

        private void  ProcessOneImage(String fullImageFileName)
        {
            String             rootName = OSservices.GetRootName(fullImageFileName);
            PicesDataBaseImage i        = dbConn.ImageLoad(rootName);

            if (i != null)
            {
                runStatsImagesInDataBase++;
                return;
            }


            String sipperFileName = null;
            uint   scanLine       = 0;
            uint   scanCol        = 0;

            PicesFeatureVector.ParseImageFileName(fullImageFileName, ref sipperFileName, ref scanLine, ref scanCol);

            if (String.IsNullOrEmpty(sipperFileName) || (scanLine < 1))
            {
                // We are not going to be able to locate this image in the Database.
                runStatsImagesNotInDataBase++;
                reconcilingRunLog.Writeln(fullImageFileName + "\t" + "Name format will not let me derive needed info.");
                return;
            }

            String sqlStr = "call  ImagesLocateClosestImage(" + "\"" + sipperFileName + "\"" + ", " + scanLine.ToString() + ", " + scanCol.ToString() + ")";

            String[][] results = dbConn.QueryStatement(sqlStr, null);
            if ((results == null) || (results.Length < 1))
            {
                runStatsImagesNotInDataBase++;
                reconcilingRunLog.Writeln(fullImageFileName + "\t" + "Could not find an appropriate image in the Database");

                RemoveImage(fullImageFileName);
                return;
            }

            String correctImageFileName = results[0][1];
            String newFullName          = OSservices.AddSlash(OSservices.GetPathPartOfFile(fullImageFileName)) +
                                          correctImageFileName + "." +
                                          OSservices.GetFileExtension(fullImageFileName);

            OSservices.RenameFile(fullImageFileName, newFullName);
            runStatsImagesFixed++;
        } /* ProcessOneImage */
Beispiel #10
0
        } /* DeriveFracPartByDepth */

        private PicesDataBaseImageList  DeriveRandomDistribution(PicesDataBase connThread,
                                                                 List <ImageEntry> images
                                                                 )
        {
            RunLogAddMsg("Extracting Images Randomly." + "\n");

            PicesDataBaseImageList randDist = new PicesDataBaseImageList();

            DateTime d               = DateTime.Now;
            int      miliSecsInDay   = d.Millisecond + d.Second * 1000 + d.Minute * 60000 + d.Hour * 360000;
            Random   randomGenerator = new Random(miliSecsInDay);

            RandomSortImageEntryList(images, randomGenerator);

            foreach (ImageEntry ie in images)
            {
                PicesDataBaseImage dbi = connThread.ImageLoad(ie.imageId);
                if (dbi == null)
                {
                    RunLogAddMsg("DeriveRandomDistribution   ***ERROR***   Could not get ImageId[" + ie.imageId + "]" + "\n");
                }
                else
                {
                    randDist.Add(dbi);
                    if ((randDist.Count % 100) == 0)
                    {
                        RunLogAddMsg("Images Extracted " + randDist.Count + " of " + images.Count + "\n");
                    }
                }

                if (randDist.Count >= howManyToHarvest)
                {
                    break;
                }
            }

            return(randDist);
        } /* DeriveRandomDistribution */
Beispiel #11
0
        private void  SaveImagesByDepthImcrements()
        {
            images.Sort(PicesDataBaseImageList.SortOrderType.soDepth, false);

            int idx = 0;
            PicesDataBaseImage i = images[0];

            while ((idx < images.Count) && (!cancelRequested))
            {
                int depthIndex    = DepthIndex(i.Depth);
                int curDepthIndex = depthIndex;

                int fromDepth = depthIndex * increments;
                int toDepth   = (depthIndex + 1) * increments;

                String depthSubDirName = fromDepth.ToString("000") + "-" + toDepth.ToString("000");
                curDir = OSservices.AddSlash(DestinationDirectory.Text) + depthSubDirName;

                try { Directory.CreateDirectory(curDir); }  catch (Exception)  {}

                PicesDataBaseImageList imagesThisDepthIndex = new PicesDataBaseImageList();

                while ((idx < images.Count) && (!cancelRequested) && (depthIndex == curDepthIndex))
                {
                    imagesThisDepthIndex.Add(i);
                    idx++;
                    if (idx < images.Count)
                    {
                        i          = images[idx];
                        depthIndex = DepthIndex(i.Depth);
                    }
                }

                SaveImagesInList(imagesThisDepthIndex, curDir);
            }
        } /* SaveImagesByDepthImcrements */
Beispiel #12
0
        public ImageViewer(PicesRaster _raster,
                           PicesDataBaseImage _image,
                           PicesClassList _classes
                           )
        {
            runLog  = new PicesRunLog();
            raster  = _raster;
            classes = _classes;
            dbConn  = PicesDataBase.GetGlobalDatabaseManagerNewInstance(runLog);
            image   = _image;

            sizeCoordinates = image.SizeCoordinates;

            if (raster == null)
            {
                raster = PicesRaster.GetOrigSipperImage(image.SipperFileName,
                                                        image.ByteOffset,
                                                        image.TopLeftRow,
                                                        image.TopLeftCol,
                                                        image.Height,
                                                        image.Width,
                                                        image.ConnectedPixelDist,
                                                        runLog
                                                        );
            }

            if (raster == null)
            {
                MessageBox.Show("Could not locate source image or SipperFile[" + image.SipperFileName + "]");
                return;
            }

            {
                uint scanLine = image.TopLeftRow;
                scanLine       = 4096 * (uint)(scanLine / 4096);
                instrumentData = dbConn.InstrumentDataGetByScanLine(image.SipperFileName, image.TopLeftRow);
                sipperFile     = dbConn.SipperFileRecLoad(image.SipperFileName);
            }

            double pixelsPerScanLine = pixelsPerScanLineDefault;


            if (instrumentData != null)
            {
                if (instrumentData.ActiveColumns > 0)
                {
                    pixelsPerScanLine = instrumentData.ActiveColumns;
                }
                if (instrumentData.FlowRate1 > 0.0)
                {
                    flowRate1 = instrumentData.FlowRate1;
                }
            }

            if (sipperFile != null)
            {
                if (sipperFile.ScanRate > 0.0)
                {
                    scanRate = sipperFile.ScanRate;
                }
                deployment = dbConn.SipperDeploymentLoad(sipperFile.CruiseName, sipperFile.StationName, sipperFile.DeploymentNum);
                if (deployment != null)
                {
                    chamberWidth = deployment.ChamberWidth;
                }
            }

            if ((dataFieldAssignments == null) || (DataLabels == null))
            {
                ConfigurationLoad();
            }

            InitializeComponent();
            if (image != null)
            {
                extractionLogEntry = dbConn.LogEntriesSelect(image.ExtractionLogEntryId);
                classLogEntry      = dbConn.LogEntriesSelect(image.ClassLogEntryId);
            }

            mmPerPixelAccrossChamber = chamberWidth * mmPerMeter / pixelsPerScanLine;
            mmPerPixelWithFlow       = mmPerMeter * flowRate1 / scanRate;

            DataLabels    = new Label[4];
            DataLabels[0] = DataLabel0;
            DataLabels[1] = DataLabel1;
            DataLabels[2] = DataLabel2;
            DataLabels[3] = DataLabel3;

            displayDataFields    = new TextBox[4];
            displayDataFields[0] = DataField0;
            displayDataFields[1] = DataField1;
            displayDataFields[2] = DataField2;
            displayDataFields[3] = DataField3;

            UpdateDataFields();

            ImageFileName.Text = image.ImageFileName;
        }
Beispiel #13
0
        private void  ImportImage(PicesDataBase threadConn,
                                  String fileName
                                  )
        {
            String rootName      = OSservices.GetRootName(fileName);
            String picesRootName = sipperFileName + "_" + rootName;

            PicesDataBaseImage dbi = threadConn.ImageLoad(picesRootName);

            if (dbi != null)
            {
                return;
            }

            PicesRaster r = new PicesRaster(fileName);

            r = r.Padded(2);

            PicesFeatureVector fv = new PicesFeatureVector(r, picesRootName, null, runLog);

            fv.ExampleFileName = picesRootName;

            int  imageId    = 0;
            bool successful = false;


            uint centroidRow = (uint)(0.5f + fv.CentroidRow);
            uint centroidCol = (uint)(0.5f + fv.CentroidCol);

            if ((centroidRow < 0) || (centroidRow > r.Height))
            {
                centroidRow = (uint)(r.Height / 2);
            }

            if ((centroidCol < 0) || (centroidCol > r.Width))
            {
                centroidCol = (uint)(r.Width / 2);
            }

            threadConn.ImageInsert(r,
                                   picesRootName,
                                   sipperFileName,
                                   0, 0, 0,
                                   (uint)r.Height, (uint)r.Width,
                                   (uint)fv.OrigSize,
                                   3,
                                   extractionLogEntryId.LogEntryId, extractionLogEntryId.LogEntryId,
                                   centroidRow, centroidCol,
                                   unknownClass, 1.0f, null, 0.0f, null,
                                   0.0f, // depth,
                                   0.0f, // Image Size
                                   null,
                                   ref imageId,
                                   ref successful
                                   );
            if (successful)
            {
                threadConn.FeatureDataInsertRow(sipperFileName, fv);
            }
            else
            {
                RunLogAddMsg("RootName[" + rootName + "] Failed: " + threadConn.LastErrorDesc() + "\n");
            }
        } /* ImportImage */
Beispiel #14
0
        private void  SaveOneBatchOfImages(String dirPath,
                                           Dictionary <String, int> imagesPerClass,
                                           PicesDataBaseImageList batch
                                           )
        {
            if (classKeyToUse == 'V')
            {
                batch.Sort(PicesDataBaseImageList.SortOrderType.soValidatedClassName, false);
            }
            else
            {
                batch.Sort(PicesDataBaseImageList.SortOrderType.soClassName, false);
            }

            int idx = 0;
            PicesDataBaseImage i = batch[0];

            while ((idx < batch.Count) && (!cancelRequested))
            {
                String className = i.Class1Name;
                if (classKeyToUse == 'V')
                {
                    className = i.ValidatedClassName;
                }

                String curClassName = className;

                String classDir = OSservices.AddSlash(dirPath) + className;

                try { OSservices.CreateDirectoryPath(classDir); }  catch (Exception)  {}

                int countThisClass = 0;
                if (imagesPerClass.ContainsKey(curClassName))
                {
                    countThisClass = imagesPerClass[curClassName];
                }
                else
                {
                    imagesPerClass.Add(curClassName, 0);
                }

                int    lastFoldNum = -1;
                String foldDir     = "";

                while ((idx < batch.Count) && (!cancelRequested) && (className == curClassName))
                {
                    int foldNum = countThisClass / imagsPerDir;

                    if (foldNum != lastFoldNum)
                    {
                        foldDir = OSservices.AddSlash(classDir) + curClassName + "_" + foldNum.ToString("000");

                        OSservices.CreateDirectoryPath(foldDir);
                        lastFoldNum = foldNum;
                    }

                    String      fullName = OSservices.AddSlash(foldDir) + i.ImageFileName + ".bmp";
                    PicesRaster r        = dbConn.ImageFullSizeFind(i.ImageFileName);
                    if (r == null)
                    {
                        imagesFailedToExtract++;
                    }
                    else
                    {
                        r.Save(fullName);
                    }
                    imagesSaved++;

                    // Get the next image to save.
                    idx++;
                    if (idx < batch.Count)
                    {
                        i         = batch[idx];
                        className = i.Class1Name;
                        if (classKeyToUse == 'V')
                        {
                            className = i.ValidatedClassName;
                        }
                    }

                    countThisClass++;
                }

                imagesPerClass[curClassName] = countThisClass;
            }
        } /* SaveOneBatchOfImages */
Beispiel #15
0
        private void  LoadNextImageFromPicesList()
        {
            if (picesImages == null)
            {
                return;
            }

            if (lastImageIndexLoaded >= picesImages.Count)
            {
                UpdateDisplayTimer.Enabled = false;
                return;
            }

            Font font = new System.Drawing.Font("Courier New", 8.0f, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));

            Image image = null;

            PicesDataBaseImage pi = picesImages[lastImageIndexLoaded];

            lastImageIndexLoaded++;

            image = pi.Thumbnail();
            if (image == null)
            {
                return;
            }

            float ratio  = 1.0f;
            int   maxDim = Math.Max(image.Height, image.Width);

            if (maxDim > 150)
            {
                ratio = 150.0f / (float)maxDim;
            }

            PictureBox pb = new PictureBox();

            pb.BorderStyle = BorderStyle.FixedSingle;

            int h = (int)((float)image.Height * ratio);
            int w = (int)((float)image.Width * ratio);

            pb.Height = h + 2;
            pb.Width  = w + 2;
            //pb.MouseDoubleClick += new System.Windows.Forms.MouseEventHandler(PicesThumbNail_MouseDoubleClick);
            pb.MouseClick += new MouseEventHandler(MouseClickEvent);
            pb.Name        = pi.ImageFileName;

            Image thumbNail = image.GetThumbnailImage(w, h, GetThumbnailImageAbort, thumbNailCallBackData);

            pb.Image = thumbNail;

            FlowLayoutPanel pan = new FlowLayoutPanel();

            pan.Size = new Size(Math.Max(170, w + 10), 200);
            //pan.Height = h + 80;
            //pan.Width  = Math.Max (160, w + 10);

            String rootName = OSservices.GetRootName(pi.ImageFileName);

            pan.Controls.Add(pb);
            TextBox tb = new TextBox();

            tb.Width = pan.Width - 8;
            tb.Text  = "Depth " + pi.Depth.ToString("##0.0");
            tb.Font  = font;
            pan.Controls.Add(tb);

            pan.BorderStyle = BorderStyle.FixedSingle;

            pan.BackColor = Color.White;

            thumbNails.Add(pan);
            ImageDisplayPanel.Controls.Add(pan);
        } /* LoadNextImageFromPicesList */
Beispiel #16
0
        protected override void Paint(Graphics graphics,
                                      Rectangle clipBounds,
                                      Rectangle cellBounds,
                                      int rowIndex,
                                      DataGridViewElementStates cellState,
                                      object value,
                                      object formattedValue,
                                      string errorText,
                                      DataGridViewCellStyle cellStyle,
                                      DataGridViewAdvancedBorderStyle advancedBorderStyle,
                                      DataGridViewPaintParts paintParts
                                      )
        {
            // Call the base class method to paint the default cell appearance.
            base.Paint(graphics,
                       clipBounds,
                       cellBounds,
                       rowIndex,
                       cellState,
                       value,
                       formattedValue,
                       errorText,
                       cellStyle,
                       advancedBorderStyle,
                       paintParts
                       );

            bool selected = ((cellState & DataGridViewElementStates.Selected) ==
                             DataGridViewElementStates.Selected);

            int borderWidth = 1;

            graphics.FillRectangle(selected ? thumbNailSelectedBrush : thumbNailBackGround, cellBounds);

            if ((value == null) || (value.GetType() != typeof(PicesDataBaseImage)))
            {
                graphics.DrawRectangle(thumbNailBorderPen, cellBounds);
                return;
            }

            PicesDataBaseImage dbImage = (PicesDataBaseImage)value;

            int availWidth  = cellBounds.Width - 2 * borderWidth - 2;
            int availHeight = cellBounds.Height - 2 * borderWidth;

            int heightNeededForText = 2 * thumbNailFont.Height // (Probability and Break-Tie) + (Size and Depth)
                                      + (String.IsNullOrEmpty(dbImage.ValidatedClassName) ? 0 : thumbNailFont.Height)
                                      + (displayClass1 ? thumbNailFont.Height : 0)
                                      + (displayClass2 ? thumbNailFont.Height : 0);

            if (!String.IsNullOrEmpty(dbImage.ValidatedClassName))
            {
                heightNeededForText += thumbNailFont.Height;
            }

            int heightAvailForImage = availHeight - heightNeededForText;

            Image displayImage = dbImage.Thumbnail();

            if ((displayImage.Height > heightAvailForImage) || (displayImage.Width > availWidth))
            {
                displayImage = MakeImageFit(displayImage, heightAvailForImage, availWidth);
            }

            // we want to paint the image in the center
            int paintRow = cellBounds.Y + borderWidth + (heightAvailForImage - displayImage.Height) / 2;
            int paintCol = cellBounds.X + borderWidth + (availWidth - displayImage.Width) / 2;

            graphics.DrawImage(displayImage, paintCol, paintRow, displayImage.Width, displayImage.Height);

            int curPixelRow = heightAvailForImage + cellBounds.Y; // This is where 1st line of text must go
            int leftCol     = cellBounds.X + borderWidth;

            if (!String.IsNullOrEmpty(dbImage.ValidatedClassName))
            {
                RectangleF rec = new RectangleF(leftCol + 20, curPixelRow - 1, cellBounds.Width - 22, thumbNailFont.Height);
                graphics.DrawString("V:", thumbNailFont, thumbNailLabelBrush, leftCol + 1, curPixelRow);
                graphics.DrawString(dbImage.ValidatedClassName, thumbNailFont, thumbNailDataBrush, rec, stringFormat);
                curPixelRow += thumbNailFont.Height;
            }

            if (displayClass1)
            {
                RectangleF rec = new RectangleF(leftCol + 20, curPixelRow - 1, cellBounds.Width - 22, thumbNailFont.Height);
                graphics.DrawString("C1:", thumbNailFont, thumbNailLabelBrush, leftCol + 1, curPixelRow);
                graphics.DrawString(dbImage.Class1Name, thumbNailFont, thumbNailDataBrush, rec, stringFormat);
                curPixelRow += thumbNailFont.Height;
            }

            if (displayClass2)
            {
                RectangleF rec = new RectangleF(leftCol + 20, curPixelRow - 1, cellBounds.Width - 22, thumbNailFont.Height);
                graphics.DrawString("C2:", thumbNailFont, thumbNailLabelBrush, leftCol + 1, curPixelRow);
                graphics.DrawString(dbImage.Class2Name, thumbNailFont, thumbNailDataBrush, rec, stringFormat);
                curPixelRow += thumbNailFont.Height;
            }

            graphics.DrawString("P:", thumbNailFont, thumbNailLabelBrush, leftCol + 1, curPixelRow);
            graphics.DrawString((dbImage.Class1Prob).ToString("##0.0%"), thumbNailFont, thumbNailDataBrush, leftCol + 20, curPixelRow);

            graphics.DrawString("B:", thumbNailFont, thumbNailLabelBrush, leftCol + 71, curPixelRow);
            graphics.DrawString((dbImage.BreakTie).ToString("##0.0%"), thumbNailFont, thumbNailDataBrush, leftCol + 90, curPixelRow);
            curPixelRow += thumbNailFont.Height;

            graphics.DrawString("S:", thumbNailFont, thumbNailLabelBrush, leftCol + 1, curPixelRow);
            graphics.DrawString(dbImage.PixelCount.ToString("###,##0"), thumbNailFont, thumbNailDataBrush, leftCol + 20, curPixelRow);

            graphics.DrawString("D:", thumbNailFont, thumbNailLabelBrush, leftCol + 71, curPixelRow);
            graphics.DrawString(dbImage.Depth.ToString("#,##0.0"), thumbNailFont, thumbNailDataBrush, leftCol + 90, curPixelRow);
            curPixelRow += thumbNailFont.Height;

            graphics.DrawRectangle(thumbNailBorderPen, cellBounds);
            for (int zed = 1; zed < borderWidth; zed++)
            {
                Rectangle r = new Rectangle(cellBounds.X + borderWidth, cellBounds.Y + borderWidth, cellBounds.Width - 2 * borderWidth, cellBounds.Height - 2 * borderWidth);
                graphics.DrawRectangle(thumbNailBorderPen, cellBounds);
            }

            return;
        } /* Paint */