/// <summary> /// Return copy of the curve filtered according to the filter settings (shorter by double the filter size) /// </summary> public double[] GetFilteredYs(double[] curve) { if (curve == null) { return(null); } double[] filteredValues = ImageDataTools.GaussianFilter1d(curve, filterPx); int padPoints = filterPx * 2 + 1; double[] filteredYs = new double[curve.Length - 2 * padPoints]; Array.Copy(filteredValues, padPoints, filteredYs, 0, filteredYs.Length); return(filteredYs); }
/// <summary> /// Set the structure bounds around the brightest structure in the image. /// The 1D projected image of the green channel is used. /// Boundaries are placed where intensity drops to half the distance between the peak and the noise floor. /// Noise floor is defined as the 20-percentile of the 1D projected image. /// </summary> public void AutoStructure() { // determine the brightest column double[] columnIntensities = ImageDataTools.GetAverageLeftright(imgG); double brightestValue = 0; int brightestIndex = 0; for (int i = 0; i < columnIntensities.Length; i++) { if (columnIntensities[i] > brightestValue) { brightestValue = columnIntensities[i]; brightestIndex = i; } } Log($"Brightest structure (G): {brightestValue} AFU at {brightestIndex}px"); // determine the 20-percentile brightness (background fluorescence) double[] sortedIntensities = new double[columnIntensities.Length]; Array.Copy(columnIntensities, sortedIntensities, columnIntensities.Length); Array.Sort(sortedIntensities); double noiseFloor = sortedIntensities[(int)(sortedIntensities.Length * .2)]; Log($"Noise floor (G): {noiseFloor} AFU"); // intensity cut-off is half-way to the noise floor double peakAboveNoise = brightestValue - noiseFloor; double cutOff = (peakAboveNoise * .5) + noiseFloor; Log($"Cut-off (G): {cutOff} AFU"); // start both structures at the brighest point, then walk away structure1 = brightestIndex; structure2 = brightestIndex; while (columnIntensities[structure1] > cutOff && structure1 > 0) { structure1--; } while (columnIntensities[structure2] > cutOff && structure2 < columnIntensities.Length - 1) { structure2++; } Log($"Automatic structure: {structure1}px - {structure2}px"); }
/// <summary> /// This is the primary analysis method for delta green and delta green over red calculations /// </summary> public void GenerateAnalysisCurves() { // determine mean pixel intensity over time between the structure markers var(structureIndex1, structureIndex2) = GetValidStructure(structure1, structure2); curveG = ImageDataTools.GetAverageTopdown(imgG, structureIndex1, structureIndex2); curveR = ImageDataTools.GetAverageTopdown(imgR, structureIndex1, structureIndex2); // create a dG channel by baseline subtracting just the green channel var(baselineIndex1, baselineIndex2) = GetValidBaseline(baseline1, baseline2); curveDeltaG = CreateBaselineSubtractedCurve(curveG, baselineIndex1, baselineIndex2); // create a d(G/R) curve by finding the G/R ratio then baseline subtracting that if (isRatiometric) { curveGoR = CreateRatioCurve(curveG, curveR); curveDeltaGoR = CreateBaselineSubtractedCurve(curveGoR, baselineIndex1, baselineIndex2); } }
/// <summary> /// Multi-scan linescans have multiple frames. /// Call this to load data for a specific frame. /// </summary> public void SetFrame(int frameNumber) { // error checking if (!isValid) { return; } int frameCount = Math.Max(pathsDataG.Length, pathsDataR.Length); if (frameNumber >= frameCount) { Log($"frame {frameNumber} cannot be called (max frame {frameCount - 1})"); return; } // load data bitmaps and create ratio if needed if (pathsDataG.Length > 0) { imgG = new ImageData(pathsDataG[frameNumber]); bmpDataG = imgG.GetBmpDisplay(); } if (pathsDataR.Length > 0) { imgR = new ImageData(pathsDataR[frameNumber]); bmpDataR = imgR.GetBmpDisplay(); } if (bmpDataG != null && bmpDataR != null) { bmpDataM = ImageDataTools.Merge(imgR, imgG, imgR); double[] dataM = new double[imgG.data.Length]; for (int i = 0; i < dataM.Length; i++) { dataM[i] = imgG.data[i] / imgR.data[i]; } imgM = new ImageData(dataM, imgG.width, imgG.height); } }
public void UpdateGraphs(bool skipUpdatesIfBusy = true) { // use pretty colors Color blue = System.Drawing.ColorTranslator.FromHtml("#1f77b4"); Color lightBlue = System.Drawing.ColorTranslator.FromHtml("#a2d1f2"); Color red = System.Drawing.ColorTranslator.FromHtml("#d62728"); Color lightRed = System.Drawing.ColorTranslator.FromHtml("#e63738"); Color green = System.Drawing.ColorTranslator.FromHtml("#2ca02c"); Color lightGreen = System.Drawing.ColorTranslator.FromHtml("#98df8a"); Color colorBaselineMarks = System.Drawing.ColorTranslator.FromHtml("#666666"); Color colorPeak = System.Drawing.ColorTranslator.FromHtml("#d62728"); Color colorZero = System.Drawing.ColorTranslator.FromHtml("#000000"); if (!lsFolder.isValid) { return; } if (skipUpdatesIfBusy && busyUpdating) { return; } else { busyUpdating = true; } // do the analysis lsFolder.GenerateAnalysisCurves(); // update the structure profile plot double[] columnPixelIndices = new double[lsFolder.imgG.width]; for (int i = 0; i < columnPixelIndices.Length; i++) { columnPixelIndices[i] = i; } formsPlot2.plt.Clear(); if ((cbR.Enabled && cbR.Checked)) { double[] columnBrightnessR = ImageDataTools.GetAverageLeftright(lsFolder.imgR); formsPlot2.plt.PlotScatter(columnPixelIndices, columnBrightnessR, markerSize: 0, color: red); } if ((cbG.Enabled && cbG.Checked)) { double[] columnBrightnessG = ImageDataTools.GetAverageLeftright(lsFolder.imgG); formsPlot2.plt.PlotScatter(columnPixelIndices, columnBrightnessG, markerSize: 0, color: green); } formsPlot2.plt.AxisAuto(0, .1); formsPlot2.plt.PlotVLine(lsFolder.structure1, color: Color.Black); formsPlot2.plt.PlotVLine(lsFolder.structure2, color: Color.Black); // update styling before the render formsPlot2.plt.YLabel("Intensity"); formsPlot2.plt.XLabel("Position (pixel number)"); formsPlot2.Render(); // update the time series plot curveToCopy = null; formsPlot1.plt.Clear(); if (cbRatio.Checked && cbRatio.Enabled) { if (cbDelta.Enabled && cbDelta.Checked) { curveToCopy = lsFolder.GetFilteredYs(lsFolder.curveDeltaGoR); formsPlot1.plt.PlotScatter(lsFolder.timesMsec, lsFolder.curveDeltaGoR, color: lightBlue, lineWidth: 0, markerSize: 2); formsPlot1.plt.PlotScatter(lsFolder.GetFilteredXs(), curveToCopy, markerSize: 0, color: blue, lineWidth: 2); formsPlot1.plt.PlotVLine(lsFolder.baseline1 * lsFolder.scanLinePeriod, color: colorBaselineMarks, lineWidth: 2); formsPlot1.plt.PlotVLine(lsFolder.baseline2 * lsFolder.scanLinePeriod, color: colorBaselineMarks, lineWidth: 2); formsPlot1.plt.PlotHLine(0, color: colorZero, lineWidth: 2); formsPlot1.plt.PlotHLine(curveToCopy.Max(), color: colorPeak, lineWidth: 2); formsPlot1.plt.YLabel("Delta G/R (%)"); } else { curveToCopy = lsFolder.GetFilteredYs(lsFolder.curveGoR); formsPlot1.plt.PlotScatter(lsFolder.timesMsec, lsFolder.curveGoR, color: lightBlue, lineWidth: 0, markerSize: 2); formsPlot1.plt.PlotScatter(lsFolder.GetFilteredXs(), curveToCopy, markerSize: 0, color: blue, lineWidth: 2); formsPlot1.plt.YLabel("G/R (%)"); formsPlot1.plt.PlotHLine(curveToCopy.Max(), color: colorPeak, lineWidth: 2); } } else if ((cbR.Checked && cbR.Enabled) && (cbG.Checked && cbG.Enabled)) { formsPlot1.plt.PlotScatter(lsFolder.timesMsec, lsFolder.curveG, markerSize: 0, color: green); formsPlot1.plt.PlotScatter(lsFolder.timesMsec, lsFolder.curveR, markerSize: 0, color: red); formsPlot1.plt.YLabel("G and R (AFU)"); } else if (cbR.Checked && cbR.Enabled) { formsPlot1.plt.PlotScatter(lsFolder.timesMsec, lsFolder.curveR, markerSize: 0, color: red); formsPlot1.plt.YLabel("R (AFU)"); } else if (cbG.Checked && cbG.Enabled) { if (cbDelta.Enabled && cbDelta.Checked) { curveToCopy = lsFolder.GetFilteredYs(lsFolder.curveDeltaG); formsPlot1.plt.PlotScatter(lsFolder.timesMsec, lsFolder.curveDeltaG, lineWidth: 0, color: lightGreen, markerSize: 2); formsPlot1.plt.PlotScatter(lsFolder.GetFilteredXs(), curveToCopy, markerSize: 0, color: green, lineWidth: 2); formsPlot1.plt.PlotVLine(lsFolder.baseline1 * lsFolder.scanLinePeriod, color: colorBaselineMarks, lineWidth: 2); formsPlot1.plt.PlotVLine(lsFolder.baseline2 * lsFolder.scanLinePeriod, color: colorBaselineMarks, lineWidth: 2); formsPlot1.plt.PlotHLine(0, color: colorZero, lineWidth: 2); formsPlot1.plt.PlotHLine(curveToCopy.Max(), color: colorPeak, lineWidth: 2); formsPlot1.plt.YLabel("Delta G (%)"); } else { curveToCopy = lsFolder.GetFilteredYs(lsFolder.curveG); formsPlot1.plt.PlotScatter(lsFolder.timesMsec, lsFolder.curveG, lineWidth: 0, color: lightGreen, markerSize: 2); formsPlot1.plt.PlotScatter(lsFolder.GetFilteredXs(), curveToCopy, markerSize: 0, color: green, lineWidth: 2); formsPlot1.plt.PlotHLine(curveToCopy.Max(), color: colorPeak, lineWidth: 2); formsPlot1.plt.YLabel("G (AFU)"); } } formsPlot1.plt.AxisAuto(.05, .1); // make ticks smaller than typical var tickFont = new Font(FontFamily.GenericMonospace, (float)10.0); //formsPlot1.plt.Ticks(font: tickFont); //formsPlot2.plt.Ticks(font: tickFont); // update styling before the render formsPlot1.plt.XLabel("Time (milliseconds)"); formsPlot1.Render(); // update peak label if (curveToCopy == null) { lblPeak.Text = $""; } else { lblPeak.Text = $"{Math.Round(curveToCopy.Max(), 2)}%"; } Application.DoEvents(); busyUpdating = false; }