【问题标题】:Calculating minimum and maximum values of a histogram计算直方图的最小值和最大值
【发布时间】:2019-01-12 08:02:12
【问题描述】:

我有一张灰度图像(有一个单波段),值范围从 -182 到 94。但是,在大多数情况下,图像的直方图只占据一个狭窄的范围,如下图所示。我有一个数组中像素的值。我想找到直方图的开始和结束(在本例中大约为 22 到 70)。是否有任何内置函数可以用来做到这一点? 我正在使用 C#、Emgu CV 和 GDAL

【问题讨论】:

  • 您能否提供一些代码来展示如何访问值。请注意,开始和结束必须由某些条件定义,毕竟真正的开始/结束显然是 -182 到 94。22 左右对您来说有何特别之处?如果直方图中有两个峰值怎么办?
  • NetMage 我有一个数组中的值,所以要访问它们,我只需索引它们。我同意开始和结束必须由某些条件定义。我试图将真正的开始/结束与直方图的开始和结束分开。 22 很特殊,因为这是直方图的起点。
  • 那么数组的索引是从 0 - end 还是从 -182 到 94 ?你怎么知道它从-182开始? “开始于”是什么意思?数组中hist[22] 之前的所有值是否都为零? -182 处的历史值是多少?

标签: c# histogram emgucv gdal


【解决方案1】:

假设您的直方图值位于名为 histint[] 中,您可以使用一些 LINQ 扩展方法来查找最大的连续值组,并找到它们在数组中的开始和结束位置。如果您的直方图仅包含一个非零区域的全零,并且不能很好地处理多个非零区域 - 它只是选择最长的水平跨度,那么这将是多余的。

var histPos = hist
                .Select((hval, pos) => new { hval, pos })
                .GroupByWhile((prev,cur) => prev.hval != 0 && cur.hval != 0)
                .MaxBy(zvg => zvg.Count())
                .Select(zvg => zvg.pos);
var start = histPos.Min();
var end = histPos.Max();

我使用的扩展方法是GroupByWhile,只要布尔 lambda 返回 true,它就会对顺序对象进行分组,MaxBy 从 lambda 返回具有最大返回值的对象。

public static class IEnumerableExt {
    // TKey combineFn((TKey Key, T Value) PrevKeyItem, T curItem):
    // PrevKeyItem.Key = Previous Key
    // PrevKeyItem.Value = Previous Item
    // curItem = Current Item
    // returns new Key
    public static IEnumerable<(TKey Key, T Value)> ScanPair<T, TKey>(this IEnumerable<T> src, TKey seedKey, Func<(TKey Key, T Value), T, TKey> combineFn) {
        using (var srce = src.GetEnumerator()) {
            if (srce.MoveNext()) {
                var prevkv = (seedKey, srce.Current);

                while (srce.MoveNext()) {
                    yield return prevkv;
                    prevkv = (combineFn(prevkv, srce.Current), srce.Current);
                }
                yield return prevkv;
            }
        }
    }

        // bool testFn(T prevItem, T curItem)
    // returns groups by sequential matching bool
    public static IEnumerable<IGrouping<int, T>> GroupByWhile<T>(this IEnumerable<T> src, Func<T, T, bool> testFn) =>
        src.ScanPair(1, (kvp, cur) => testFn(kvp.Value, cur) ? kvp.Key : kvp.Key + 1)
           .GroupBy(kvp => kvp.Key, kvp => kvp.Value);

    public static T MaxBy<T, TKey>(this IEnumerable<T> src, Func<T, TKey> keySelector, Comparer<TKey> keyComparer) => src.Aggregate((a, b) => keyComparer.Compare(keySelector(a), keySelector(b)) > 0 ? a : b);
    public static T MaxBy<T, TKey>(this IEnumerable<T> src, Func<T, TKey> keySelector) => src.Aggregate((a, b) => Comparer<TKey>.Default.Compare(keySelector(a), keySelector(b)) > 0 ? a : b);    
}

【讨论】:

    【解决方案2】:

    如果我理解正确,您可以将像素视为 sbyte 数组, 在这种情况下,这对我有用:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace ConsoleMinMax
    {
        class Program
        {
            static void Main(string[] args)
            {
                sbyte[] array1 = { 1, -1, -2, 0, 99, -111 };
    
                MinMax(array1);
    
                void MinMax(sbyte[] array)
                {
                    // Report minimum and maximum values.
                    Console.WriteLine("max = {0}; min = {1}", array.Max(), array.Min());
                }
            }
        }
    }
    

    【讨论】:

    • 这只是查找数组中的最大值和最小值。我想将直方图的起点/终点与真实的起点/终点分开。
    猜你喜欢
    • 1970-01-01
    • 2015-10-29
    • 1970-01-01
    • 2020-12-23
    • 2012-11-21
    • 1970-01-01
    • 1970-01-01
    • 2015-12-03
    • 1970-01-01
    相关资源
    最近更新 更多