/// <summary> /// Computes a confusion matrix using the soft values from the distributions in <paramref name="inferredLabels"/> based upon the ground truth /// pixel labels in <paramref name="groundTruth"/>, and adds them to <paramref name="matrix"/>. /// </summary> /// <param name="matrix">Matrix to add the confusion values of this image to</param> /// <param name="groundTruth">The ground truth labels of the image</param> /// <param name="inferredLabels">The inferred labels of the image</param> public static unsafe void ComputeConfusionMatrix(ConfusionMatrix matrix, LabelImage groundTruth, DistributionImage inferredLabels) { int rows = groundTruth.Rows; int columns = groundTruth.Columns; int channels = inferredLabels.Channels; fixed(short *labelsSrc = groundTruth.RawArray) { fixed(float *distSrc = inferredLabels.RawArray) { short *labelsPtr = labelsSrc; float *distPtr = distSrc; for (int r = 0; r < rows; r++) { for (int c = 0; c < columns; c++, labelsPtr++) { short trueLabel = *labelsPtr; for (short i = 0; i < channels; i++, distPtr++) { matrix.Add(trueLabel, i, *distPtr); } } } } } }
/// <summary> /// Creates a label image by sampling from the distribution. Labels chosen are constricted to belong to <paramref name="set"/>, thus using it /// as a hard prior over labels. /// </summary> /// <param name="set">Set used to constrict the sampling</param> /// <returns>A label image</returns> public unsafe LabelImage GenerateLabels(LabelSet set) { int rows = Rows; int columns = Columns; int numLabels = Channels; int setSize = set.Count; LabelImage result = new LabelImage(Rows, Columns); int count = rows * columns; GibbsImage[] gibbs = new GibbsImage[set.Count]; short[] labels = set.OrderBy(o => o).ToArray(); float[] prior = new float[set.Count]; for (int i = 0; i < labels.Length; i++) { gibbs[i] = new GibbsImage(rows, columns); gibbs[i].Add(this, labels[i]); prior[i] = 1f / set.Count; } int samples = rows * columns; int row, column; row = column = 0; for (int i = 0; i < samples; i++) { int index = (short)prior.Sample(); gibbs[index].Sample(ref row, ref column); result[row, column] = labels[index]; } return(result); }
/// <summary> /// Computes a confusion matrix using the soft values from the distributions in <paramref name="inferredLabels"/> based upon the ground truth /// pixel labels in <paramref name="groundTruth"/>. /// </summary> /// <param name="groundTruth">The ground truth labels of the image</param> /// <param name="inferredLabels">The inferred labels of the image</param> /// <returns>A confusion matrix</returns> public static ConfusionMatrix ComputeConfusionMatrix(LabelImage groundTruth, DistributionImage inferredLabels) { ConfusionMatrix matrix = new ConfusionMatrix(inferredLabels.Channels); ComputeConfusionMatrix(matrix, groundTruth, inferredLabels); return(matrix); }
/// <summary> /// Computes a confusion matrix from <paramref name="inferredLabels"/> using <paramref name="trueLabels"/> as a reference. /// </summary> /// <param name="numLabels">The number of possible labels</param> /// <param name="trueLabels">The true labels of an image</param> /// <param name="inferredLabels">The inferred labels of an image</param> /// <returns>A confusion matrix</returns> public static unsafe ConfusionMatrix ComputeConfusionMatrix(int numLabels, LabelImage trueLabels, LabelImage inferredLabels) { ConfusionMatrix matrix = new ConfusionMatrix(numLabels); ComputeConfusionMatrix(matrix, trueLabels, inferredLabels); return(matrix); }
/// <summary> /// Creates several splits of the dataset. /// </summary> /// <param name="sampleFrequency">How often to sample pixels within the training images.</param> /// <param name="boxRows">Vertical trim around the edges of images to avoid feature tests beyond the boundary of the image</param> /// <param name="boxColumns">Vertical trim around the edges of images to avoid feature tests beyond the boundary of the image</param> /// <param name="numSplits">Number of splits to create</param> /// <returns>Splits of the data</returns> public List <ImageDataPoint <T> >[] CreateDataPoints(int sampleFrequency, int boxRows, int boxColumns, int numSplits) { List <ImageDataPoint <T> > points = new List <ImageDataPoint <T> >(); foreach (LabeledImage <T> labelledImage in _images) { IMultichannelImage <T> image = labelledImage.Image; LabelImage labels = labelledImage.Labels; LabelSet set = labels.Labels; string id = labelledImage.ID; bool[,] valid = labelledImage.Valid; int maxRows = image.Rows - boxRows; int maxColumns = image.Columns - boxColumns; for (int r = boxRows; r < maxRows; r += sampleFrequency) { for (int c = boxColumns; c < maxColumns; c += sampleFrequency) { short label = getLabel(labels[r, c], set); bool sample = valid[r, c]; if (sample && label == LabelImage.BackgroundLabel) { switch (_backgroundSampleMode) { case BackgroundSampleMode.Ignore: sample = false; break; case BackgroundSampleMode.Half: sample = ThreadsafeRandom.Test(.5); break; } } if (sample) { points.Add(new ImageDataPoint <T>(image, (short)r, (short)c, label)); } } } } List <ImageDataPoint <T> >[] splits = new List <ImageDataPoint <T> > [numSplits]; for (int i = 0; i < numSplits; i++) { if (_byImage) { splits[i] = sampleByImage(points); } else { splits[i] = sample(points); } } return(splits); }
/// <summary> /// Computes the inverse label frequency array for the image. This is an array in which each index holds a value equal /// to the total number of image labels divided by the total number of that particular label. /// </summary> /// <param name="numLabels">Total number of labels</param> /// <returns>Inverse label frequency</returns> public unsafe float[] ComputeInverseLabelFrequency(int numLabels) { int[] counts = new int[numLabels]; foreach (LabeledImage <T> image in _images) { LabelImage labels = image.Labels; LabelSet set = labels.Labels; fixed(short *labelsSrc = labels.RawArray) { int count = labels.Rows * labels.Columns; short *labelsPtr = labelsSrc; while (count-- > 0) { short index = getLabel(*labelsPtr++, set); bool sample = true; if (index == LabelImage.BackgroundLabel) { switch (_backgroundSampleMode) { case BackgroundSampleMode.Ignore: sample = false; break; case BackgroundSampleMode.Half: sample = ThreadsafeRandom.Test(.5); break; } } if (!sample) { continue; } counts[index]++; } } } float[] frequency = new float[numLabels]; float sum = 0; for (short i = 0; i < frequency.Length; i++) { frequency[i] = 1 + counts[i]; sum += frequency[i]; } for (int i = 0; i < frequency.Length; i++) { frequency[i] = sum / frequency[i]; } return(frequency); }
/// <summary> /// Computes a confusion matrix from <paramref name="inferredLabels"/> using <paramref name="trueLabels"/> as a reference, and adds /// the information into <paramref name="matrix"/>. /// </summary> /// <param name="matrix">The matrix that will hold the results</param> /// <param name="trueLabels">The true labels of an image</param> /// <param name="inferredLabels">The inferred labels of an image</param> public static unsafe void ComputeConfusionMatrix(ConfusionMatrix matrix, LabelImage trueLabels, LabelImage inferredLabels) { fixed(short *trueLabelsSrc = trueLabels.RawArray, inferredLabelsSrc = inferredLabels.RawArray) { short *trueLabelsPtr = trueLabelsSrc; short *inferredLabelsPtr = inferredLabelsSrc; int count = trueLabels.Rows * trueLabels.Columns; while (count-- > 0) { short row = *trueLabelsPtr++; short column = *inferredLabelsPtr++; if (row == BackgroundLabel) { continue; } matrix.Add(row, column); } } }
/// <summary> /// Converts to a label image using the maximum likelihood labels of this image's pixels. /// </summary> /// <returns>A label image</returns> public unsafe LabelImage ToLabelImage() { LabelImage labels = new LabelImage(Rows, Columns); fixed(short *labelsSrc = labels.RawArray) { fixed(float *dataSrc = RawArray) { float *dataPtr = dataSrc; short *labelsPtr = labelsSrc; int rows = Rows; int columns = Columns; int channels = Channels; for (int r = 0; r < rows; r++) { for (int c = 0; c < columns; c++) { short max = -1; float maxValue = float.MinValue; for (short i = 0; i < channels; i++) { float test = *dataPtr++; if (test > maxValue) { maxValue = test; max = i; } } *labelsPtr++ = max; } } } } return(labels); }
/// <summary> /// Adds a label image to the distribution. Each time the label in <paramref name="labels"/> matches <paramref name="label"/>, the value at that pixel /// is incremented by 1. /// </summary> /// <param name="labels">Label image to add</param> /// <param name="label">The label to extract</param> public unsafe void Add(LabelImage labels, short label) { int rows = labels.Rows; int columns = labels.Columns; int nRows = Rows; int nColumns = Columns; float scaleR = (float)nRows / rows; float scaleC = (float)nColumns / columns; float[,] counts = new float[nRows, nColumns]; fixed(short *labelSrc = labels.RawArray) { short *labelPtr = labelSrc; for (int r = 0; r < rows; r++) { for (int c = 0; c < columns; c++) { short test = *labelPtr++; if (test == label) { float rr = r * scaleR; float cc = c * scaleC; int i0 = (int)rr; int j0 = (int)cc; float di = rr - i0 - .5f; float dj = cc - j0 - .5f; if (di < 0) { i0--; di += 1; } if (dj < 0) { j0--; dj += 1; } int i1 = i0 + 1; int j1 = j0 + 1; if (i0 < 0) { i0++; } if (i1 == nRows) { i1--; } if (j0 < 0) { j0++; } if (j1 == nColumns) { j1--; } float a = 1 - di; float b = 1 - dj; counts[i0, j0] += a * b; counts[i0, j1] += a * dj; counts[i1, j0] += di * b; counts[i1, j1] += di * dj; _sum += 1; _rowSums[i0] += a; _rowSums[i1] += di; _columnSums[j0] += b; _columnSums[j1] += dj; } } } } fixed(float *dataSrc = RawArray, countsSrc = counts) { float *dataPtr = dataSrc; float *countsPtr = countsSrc; int total = Rows * Columns; while (total-- > 0) { *dataPtr = *dataPtr + *countsPtr; dataPtr++; countsPtr++; } } }
/// <summary> /// Constructor. /// </summary> /// <param name="image">The source image</param> /// <param name="labels">The ground truth labels</param> public LabeledImage(IMultichannelImage <T> image, LabelImage labels) { Image = image; Labels = labels; initValid(); }
/// <summary> /// Scales this image to another size using exact scaling (no interpolation). /// </summary> /// <param name="subsample">The sampling rate</param> /// <returns>The scaled image</returns> public unsafe LabelImage Subsample(int subsample) { if (_labelCounts == null) { updateLabelCounts(); } int rows = Rows; int columns = Columns; int stride = columns; int nRows = rows / subsample; int nColumns = columns / subsample; int numLabels = -1; foreach (short key in _labelCounts.Keys) { numLabels = Math.Max(numLabels, key); } numLabels++; short[, ,] dst = new short[nRows, nColumns, 1]; fixed(short *srcBuf = RawArray, dstBuf = dst) { short *srcPtr = srcBuf; short *dstPtr = dstBuf; for (int r = 0; r < nRows; r++) { short *srcScan = srcPtr; for (int c = 0; c < nColumns; c++) { int[] counts = new int[numLabels]; short *srcScan2 = srcScan; for (int srcR = 0; srcR < subsample; srcR++) { short *srcScan3 = srcScan2; for (int srcC = 0; srcC < subsample; srcC++) { counts[*srcScan3++]++; } srcScan2 += stride; } int maxValue = -1; short max = -1; for (short i = 0; i < numLabels; i++) { if (counts[i] > maxValue) { maxValue = counts[i]; max = i; } } *dstPtr++ = max; srcScan += subsample; } srcPtr += stride * subsample; } } LabelImage labels = new LabelImage(); labels.SetData(dst); return(labels); }