[C#] Zliczanie pikseli

przonak007
Użytkownik
Użytkownik
Posty: 46
Rejestracja: 15 kwie 2009, o 17:31
Płeć: Mężczyzna
Lokalizacja: wałbrzych
Podziękował: 1 raz

[C#] Zliczanie pikseli

Post autor: przonak007 »

Piszę program w C#. I mam taką zagwostkę. Jak zliczyć ilość pixeli na zaznaczonym obszarze ? od czego zacząć ?
Ostatnio zmieniony 16 wrz 2013, o 11:17 przez Afish, łącznie zmieniany 1 raz.
Powód: Poprawa wiadomości.
zeus_156
Użytkownik
Użytkownik
Posty: 36
Rejestracja: 9 sie 2013, o 15:16
Płeć: Mężczyzna
Lokalizacja: KRK
Pomógł: 7 razy

[C#] Zliczanie pikseli

Post autor: zeus_156 »

Możesz to doprecyzować?
Piksle, które liczysz są na ekranie, w pliku z bitmapą, tablica w pamięci?
Czy zaznaczony obszar jest regularny (prostokąt, wielobok foremny, koło), czy może wręcz przeciwnie (np. obszar zaznczony przez użytkownika narzędziem "free form")?
Czy można założyć że zaznaczony obszar jest figurą wypukłą?
Zliczasz wszystkie piksle czy tylko o określonym kolorze?
przonak007
Użytkownik
Użytkownik
Posty: 46
Rejestracja: 15 kwie 2009, o 17:31
Płeć: Mężczyzna
Lokalizacja: wałbrzych
Podziękował: 1 raz

[C#] Zliczanie pikseli

Post autor: przonak007 »

Zliczam wszystkie pixele, bez wyjątku. Obszar się zmienia, sam tworzę obszar do wyliczanie, który może przybierać różne kształty (wielokąt).
Zdjęcie może być wformacje jpeg, bitmapa, png. Załączam też funkcje dzięki której tworzę obszar do wyliczenia:

Kod: Zaznacz cały

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows.Forms;


namespace testowanie_powierzchni
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        private List<PointF> m_Points = new List<PointF>();

        private void Form1_MouseClick(object sender, MouseEventArgs e)
        {
            m_Points.Add(new PointF(e.X, e.Y));
            this.Invalidate();
        }
     
        private void Form1_Paint(object sender, PaintEventArgs e)
        {
          
            if (m_Points.Count >= 2)
            {
               
                e.Graphics.DrawPolygon(Pens.Blue, m_Points.ToArray());
            }
            if (m_Points.Count > 0)
            {
                foreach (PointF pt in m_Points)
                {
                  
                    e.Graphics.FillRectangle(Brushes.Black, pt.X - punkt, pt.Y - punkt, punkt, punkt);
                   
                }
            }
        }

         private void wczytywanieToolStripMenuItem_Click(object sender, EventArgs e)
        {
            var image = new System.Windows.Forms.OpenFileDialog();
            image.Filter = "";
            image.Title = "Select image";
            if (image.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                System.IO.FileInfo File = new System.IO.FileInfo(image.FileName);
                BackgroundImage = Image.FromFile(image.FileName);
            }
        }

}
zeus_156
Użytkownik
Użytkownik
Posty: 36
Rejestracja: 9 sie 2013, o 15:16
Płeć: Mężczyzna
Lokalizacja: KRK
Pomógł: 7 razy

[C#] Zliczanie pikseli

Post autor: zeus_156 »

Widzę, że masz trudny przypadek - użytkownik może wprowadzić kompletnie dowolne punkty. Dlatego zanim zaczniesz liczyć powinieneś sprawdzić czy wybrany algorytm jest w stanie to policzyć, czy raczej uzyskana wartość będzie bezsensowna. Pozwól że przedstawię kilka przykładów:
\(\displaystyle{ \begin{picture}(200,140)
\put(85,80){\makebox(0,0){$obszar \ wypukly$}}
%
\put(70,70){\circle*{4}}
\put(70,70){\vector(1,0){30}}
\put(100,70){\vector(1,-1){10}}
\put(110,60){\vector(-1,-1){10}}
\put(100,50){\vector(-1,0){30}}
\put(70,50){\vector(-1,1){10}}
\put(60,60){\vector(1,1){10}}
\end{picture}}\)
; \(\displaystyle{ \begin{picture}(200,140)
\put(90,90){\makebox(0,0){$obszar \ wklesly$}}
%
\put(70,70){\circle*{4}}
\put(70,70){\vector(1,0){20}}
\put(90,70){\vector(0,-1){10}}
\put(90,60){\vector(-1,0){10}}
\put(80,60){\vector(0,-1){10}}
\put(80,50){\vector(1,0){20}}
\put(100,50){\vector(0,1){30}}
\put(100,80){\vector(1,0){10}}
\put(110,80){\vector(0,-1){30}}
\put(110,50){\vector(1,0){10}}
\put(120,50){\vector(0,-1){10}}
\put(120,40){\vector(-1,0){50}}
\put(70,40){\vector(0,1){30}}
\end{picture}}\)
; \(\displaystyle{ \begin{picture}(200,140)
\put(90,90){\makebox(0,0){$obszar \ z \ przecinajacymi \ liniami$}}
%
\put(70,70){\circle*{4}}
\put(70,70){\vector(1,0){20}}
\put(90,70){\vector(0,-1){10}}
\put(90,60){\vector(-1,0){10}}
\put(80,60){\vector(0,-1){10}}
\put(80,50){\vector(1,0){20}}
\put(100,50){\vector(0,1){15}}
\put(100,65){\vector(-1,0){40}}
\put(60,65){\vector(0,1){15}}
\put(60,80){\vector(1,0){25}}
\put(85,80){\vector(0,-1){35}}
\put(85,45){\vector(-1,0){15}}
\put(70,45){\vector(0,1){25}}
\end{picture}}\)

Z tego też powodu powinniśmy sprawdzić czy obszar jest wypukły i żadne linie się nie przecinają.
Następnie wyznaczyć środek (przez wyliczenie średniej ze współrzędnych punktów) i podzielić obszar na trójkąty (środek obszaru + dwa sąsiednie punkty). Teraz pozostaje wyliczyć sumę z obszarów wszystkich trójkątów (nie zapomnij o trójkącie zawierającego pierwszy i ostatni punkt).
Pozostałe przypadki są trudniejsze w realizacji, więc zostaw je sobie na deser, a na razie zrób ładny komunikat, że liczenie takiej skomplikowanej figury nie zostało jeszcze zaimplementowane.
Czy wiesz jak sprawdzić, że obszar jest wypukły?

-- 21 wrz 2013, o 10:54 --

Brak odpowiedzi znaczy, że nie. Możesz skorzystać np. z takiego kodu:

Kod: Zaznacz cały

    private static bool IsConvexPolygon()
    {
      if (!IsPolygon()) return false;  
      int rightTurns = 0;
      int leftTurns  = 0;
      PointF start    = m_Points[(m_Points.Count - 2)];
      PointF end      = m_Points[(m_Points.Count - 1)];
      PointF next;
      foreach(var p in m_Points)
      {
        next = p;
        if (IsRightTurn(start, end, next)) 
          rightTurns++;
        else 
          leftTurns++; 
        start = end;
        end = next;
      }
      return ((rightTurns > 0) && (leftTurns == 0)) 
          || ((leftTurns > 0) && (rightTurns == 0));
    }     
    private static bool IsPolygon()
    {
      return m_Points.Count >= 3; 
    } 
    private static bool IsRightTurn(PointF start, PointF end, PointF next)
    {
      double a = GetVectorAngle(start, end);
      double b = GetVectorAngle(end, next);
      return CalculateAngleDifference(a, b) < 0;
    }
    private static double GetVectorAngle(PointF start, PointF end)
    {  
      double output = 0;
      if (end.Y - start.Y == 0)
      {
        if (end.X - start.X > 0) 
          output = 0;
        else 
          output = Math.PI;  
      }
      else
      {
        output = Math.Atan((end.X - start.X) / (end.Y - start.Y));
        if (end.X - start.X < 0)
        {
          output += output > 0 ? -1 * Math.PI : Math.PI;  
        }
      }
      return output; 
    }
    private static double CalculateAngleDifference(double first, double second)
    {  
      double output = second - first;
      if (output > Math.PI)
        output -= 2 * Math.PI;
      if (output < -1 * Math.PI)
        output += 2 * Math.PI;
      return output; 
    }
Jak użyjesz metodyIsConvexPolygon() to ona zwróci informację czy zawartość m_Points jest obszarem wypukłym. Zanim będzie to można policzyć metodą trójkątów trzeba jeszcze sprawdzić czy linie pomiędzy punktami z m_Points nie przecinają się.
Czy masz pomysł jak to zrobić?-- 21 wrz 2013, o 11:00 --A zapomniałem o jednej rzeczy aby to działało w Twoim kodzie usuń static z każdej metody w tym przykładzie powyżej.
przonak007
Użytkownik
Użytkownik
Posty: 46
Rejestracja: 15 kwie 2009, o 17:31
Płeć: Mężczyzna
Lokalizacja: wałbrzych
Podziękował: 1 raz

[C#] Zliczanie pikseli

Post autor: przonak007 »

Dziękuje za pomoc . Trochę kombinowałem i jakoś to zrobiłem . Dziękuje za pomoc
ODPOWIEDZ