none
已知一个bitmap,并且已放置在Image控件中,请问如何在Image上显示某一个像素的坐标,要求显示的坐标内容在该像素的位置附近 RRS feed

  • 问题

  • 1、在做一个坏点检测的项目,像素为480*320

    2、准备使用某个控件画每一个像素的,但是像素太大,画图效率很低

    3、故将坏点数据做出了位图,但是没有较好的办法显示该


    2019年9月10日 7:07

全部回复

  • 我照你的题目要求 弄了个

    不清楚是否你和说的一致



    这个例子采用adorner+附加属性,本来想用behavior,不过都是差不多的感觉。

    没做过多的数据验证,可以自己改

    图片类(获取图片像素 )采用的是这位博主的方法

    /// <summary>
        /// 用于获取位图像素的类
        /// </summary>
        public class Imghelper
        {
            /// <summary>
            /// 位图宽度
            /// </summary>
            public int Width { get; protected set; }
            /// <summary>
            /// 位图高度
            /// </summary>
            public int Height { get; protected set; }
            /// <summary>
            /// 像素
            /// </summary>
            public Color[][] Pixels { get; protected set; }
    
            /// <summary>
            /// 根据指定的位图生成BitmapPixelHelper类的新实例。
            /// </summary>
            /// <param name="bitmap">指定的位图</param>
            public Imghelper(BitmapSource bitmap)
            {
                FormatConvertedBitmap newBitmap = new FormatConvertedBitmap(bitmap, PixelFormats.Bgra32, BitmapPalettes.WebPaletteTransparent, 0);
                const int bytesPerPixel = 4;
                Height = newBitmap.PixelHeight;
                Width = newBitmap.PixelWidth;
                byte[] data = new byte[Height * Width * bytesPerPixel];
                newBitmap.CopyPixels(data, Width * bytesPerPixel, 0);
    
                Pixels = new Color[Height][];
                for (int i = 0; i < Height; ++i)
                {
                    Pixels[i] = new Color[Width];
                    for (int j = 0; j < Width; ++j)
                    {
                        Pixels[i][j] = Color.FromArgb(
                            data[(i * Width + j) * bytesPerPixel + 3],
                            data[(i * Width + j) * bytesPerPixel + 2],
                            data[(i * Width + j) * bytesPerPixel + 1],
                            data[(i * Width + j) * bytesPerPixel + 0]);
                    }
                }
            }
    
            /// <summary>
            /// 获取图片的平均色
            /// </summary>
            public Color GetAverageColor()
            {
                int a = 0, r = 0, g = 0, b = 0;
                for (int i = 0; i < Height; ++i)
                {
                    for (int j = 0; j < Width; ++j)
                    {
                        a += Pixels[i][j].A;
                        r += Pixels[i][j].R;
                        g += Pixels[i][j].G;
                        b += Pixels[i][j].B;
                    }
                }
                a = a / Height / Width;
                r = r / Height / Width;
                g = g / Height / Width;
                b = b / Height / Width;
                return Color.FromArgb((byte)a, (byte)r, (byte)g, (byte)b);
            }
        }

    Adorner类

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Documents;
    using System.Windows.Media;
    
    namespace WpfApp6
    {
        public class ShowImagePixelsPopup : Adorner
        {
    
            private TextBlock GetTextBlock;
            private VisualCollection collection;
            private UIElement _UIElement;
            private Border GetBorder;
    
    
            public ShowImagePixelsPopup(UIElement adornedElement) : base(adornedElement)
            {
                collection = new VisualCollection(this);
    
                GetTextBlock = new TextBlock();
    
                GetTextBlock.Height = 20;
                GetTextBlock.Width = 120;
                GetTextBlock.Background = new SolidColorBrush(Colors.Wheat); 
                GetTextBlock.HorizontalAlignment = HorizontalAlignment.Left;
                GetTextBlock.VerticalAlignment = VerticalAlignment.Top;
                GetBorder = new Border();
                GetBorder.Height = 15;
                GetBorder.Width = 15;
                GetBorder.HorizontalAlignment = HorizontalAlignment.Left;
                GetBorder.VerticalAlignment = VerticalAlignment.Top;
                collection.Add(GetTextBlock);
                collection.Add(GetBorder);
                _UIElement = adornedElement;
            }
            protected override int VisualChildrenCount => collection.Count;
    
    
            protected override Visual GetVisualChild(int index) => collection[index];
    
    
            protected override Size MeasureOverride(Size constraint) => base.MeasureOverride(constraint);
    
            public void SetData(Point MousePoint, String Pixels,Color color)
            {
                GetTextBlock.Margin = new Thickness(MousePoint.X+15, MousePoint.Y-15, 0,0);
                GetBorder.Margin = new Thickness(MousePoint.X-7.5 , MousePoint.Y-7.5 , 0, 0);
                GetBorder.Background = new SolidColorBrush(color);
                GetTextBlock.Text = Pixels;
            }
    
            protected override Size ArrangeOverride(Size finalSize)
            {
                GetTextBlock.Arrange(new Rect(finalSize));
                GetBorder.Arrange(new Rect(finalSize));
                return base.ArrangeOverride(finalSize);
    
            }
        }
    }

    附加属性类

    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows;
    using System.Windows.Documents;
    using System.Windows.Controls;
    using System.Windows.Media.Imaging;

    namespace WpfApp6
    {
        public class IsShowImagePixels
        {
            public static readonly DependencyProperty IsShowImagePixelsProperty = DependencyProperty.RegisterAttached("IsShowImagePixels", typeof(bool), typeof(IsShowImagePixels), new PropertyMetadata(false, new PropertyChangedCallback(OnIsShowImagePixelsChanged)));

            public static void SetIsShowImagePixels(DependencyObject d, bool value) => d.SetValue(IsShowImagePixelsProperty, value);

            public static bool GetIsShowImagePixels(DependencyObject d) => (bool)d.GetValue(IsShowImagePixelsProperty);

            public static readonly DependencyProperty ShowImagePixelsPointProperty = DependencyProperty.RegisterAttached("ShowImagePixelsPoint", typeof(Point), typeof(IsShowImagePixels), new PropertyMetadata(new Point(0, 0),new PropertyChangedCallback(OnShowImagePixelsPointChanged)));

            public static void SetIsShowImagePixelsPoint(DependencyObject d, Point value) => d.SetValue(ShowImagePixelsPointProperty, value);

            public static Point GetShowImagePixelsPoint(DependencyObject d) => (Point)d.GetValue(ShowImagePixelsPointProperty);

            private static void OnShowImagePixelsPointChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
            {
                var c =(Point)e.NewValue;

                popup.SetData(c, $"X={(((int)c.X - 1) < 0 ? 0 : (int)c.X - 1)},Y={(((int)c.Y - 1) < 0 ? 0 : (int)c.Y - 1)}", imghelper.Pixels[((int)c.Y - 1) < 0 ? 0 : (int)c.Y - 1][((int)c.X - 1) < 0 ? 0 : (int)c.X - 1]);

            }
            private static AdornerLayer layer;
            private static Imghelper imghelper;
            private static ShowImagePixelsPopup popup;

            private static void OnIsShowImagePixelsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
            {

                var NewValue = (bool)e.NewValue;
                UIElement element = d as UIElement;
                if (!NewValue)
                {

                    AdornerLayer l = AdornerLayer.GetAdornerLayer(element);
                    var ado = l.GetAdorners(element);
                    for (var o = 0; o < ado.Length; o++)
                        l.Remove(ado[o]);
                    element.MouseMove -= Element_MouseMove;
                   
                    imghelper = null;
                    popup = null;
                    layer = null;
                    element = null;
                }
                if (element == null)
                    return;
                layer = AdornerLayer.GetAdornerLayer(element);
                popup = new ShowImagePixelsPopup(element);
                layer.Add(popup);
                imghelper = new Imghelper((element as Image).Source as BitmapSource);
                //显示鼠标位置
                element.MouseMove += Element_MouseMove;       
            }

            

            private static void Element_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
            {

                var c = e.GetPosition(sender as FrameworkElement);
                //此处只是用了鼠标位置,也可以用ShowImagePixelsPoint直接指定位置
                popup.SetData(c, $"X={(((int)c.X - 1) < 0 ? 0 : (int)c.X - 1)},Y={(((int)c.Y - 1) < 0 ? 0 : (int)c.Y - 1)}", imghelper.Pixels[((int)c.Y - 1) < 0 ? 0 : (int)c.Y - 1][((int)c.X - 1) < 0 ? 0 : (int)c.X - 1]);

            }
        }
    }


    xaml代码

    <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="*"/>
                <RowDefinition Height="auto"/>
            </Grid.RowDefinitions>
            <AdornerDecorator Grid.Row="0">
                <Image x:Name="img"  />
            </AdornerDecorator>
            <Button Click="Button_Click" Grid.Row="1" Height="40" Content="ShowOrNot"/>
        </Grid>

    cs页面代码

    public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
                var b = new BitmapImage(new Uri("timg.jpg", UriKind.RelativeOrAbsolute));
                Imghelper imghelper = new Imghelper(b);
                img.Source = b;
                img.SetValue(IsShowImagePixels.IsShowImagePixelsProperty, true);
                Set = true;
            }
            private bool Set = false;
            private void Button_Click(object sender, RoutedEventArgs e)
            {
               
                if (Set)
                    Set = false;
                else
                    Set = true;
                img.SetValue(IsShowImagePixels.IsShowImagePixelsProperty, Set);
                return;
    
            }
        }




    2019年9月10日 16:14
  • 膜拜大佬,非常感谢。

    自己在上一层添加了TextBlock,用于显示像素的坐标信息,通过坐标转换Binding了TextBlock的Margin属性,使得TextBlock的位置始终在像素点处。

    但是当显示坐标信息的像素很靠近的时候,TextBlock就会重叠。尝试过使用鼠标事件控制是否可见属性,但是当属性为不可见后,鼠标事件就不会触发了。。。

    不知道还有什么好办法可以避免重叠的问题?

    2019年9月11日 6:27
  • 重叠?

    是指textblock和其他textblock重叠?

    还是textblock自然重叠?

    没太懂

    2019年9月11日 6:47
  • 相邻像素的TextBlock重叠。

    如上图中的那里其实有3个标红的像素点,对应三个TextBlock。

    另TextBlock的位置默认为像素点的右下角,长宽固定。当超出右下边框的时候会做相应变换。

    2019年9月11日 7:37
  • 给textblock的背景色

    制造出层叠感

    鼠标点击时可以让显示顺序变换(index)

    2019年9月11日 7:52
  • 按大神提供的思路已解决该问题,非常感谢。
    2019年9月12日 4:28