Computer Hardware Forum - TweakPC

Computer Hardware Forum - TweakPC (https://www.tweakpc.de/forum/)
-   Programmiersprachen (https://www.tweakpc.de/forum/programmiersprachen/)
-   -   [C++] Problem bei Denkaufgabe (https://www.tweakpc.de/forum/programmiersprachen/78696-c-problem-bei-denkaufgabe.html)

kanonenfutter 26.09.2010 09:19

[C++] Problem bei Denkaufgabe
 
Hi Leutz :)

Also ich sitze gerade an einem Programm, welches ich als Projekt in der Uni abgeben muss. Thema: Demonstration von Bildverarbeitungsbefehlen in C++. So weit so gut. Mein Problem hier ist allerdings sehr allgemeiner Kultur, hat also nicht viel mit C++ oder BV im speziellen zu tun.

Und zwar folgendes: Ich habe ein Fenster mit einem Bild drin. Außerdem ist in dem Fenster ein Balken (quasi ein Schieberegler), über den ich einen Wert alpha einstellen kann (von 0 bis 1). Umso höher alpha, desto stärker wird das Bild geschärft. Ich arbeite über das gesamte Projekt hinweg (dies hier ist nur eine Teilaufgabe) mit der Bibliothek "CImg". Ich verwende daher keine normale Windowsoberfläche (da nicht möglich), sondern bastel mir meine wenigen benötigten Eingabeelemente einfach selbst ;)

Mal kurz zur Vorstellung:

[IMG]http://www.tweakpc.de/forum/members/kanonenfutter-albums-test-picture1641-bv-c.jpg[/IMG]

Mittlerweile hab ich nach einigem geistigem Spagat schonmal geschafft, dass die Höhe des Balkens korrekt gezeichnet wird, je nach eingestelltem alpha.

Mein Problem nun ist, dass ich aus der y-Position des Mausklicks (Achtung: beim Bildkoordinatensystem liegt der Ursprung links oben, y wird nach unten also immer größer), das entsprechende alpha berechnen muss. Hierzu hab ich zwar schon mehrere in Frage kommende Formeln durch, allerdings liefert keine das Ergebnis das ich suche.

Ich möchte mal kurz die verwendeten Maße versuchen zu verdeutlichen. Das Bild ist fest 450px hoch, über und unter dem Balken befinden sich jeweils 25px+Schriftgröße (im aktuellen Fall bei Schriftgröße 24 = insgesamt 49px) Platz zum Fensterrand.

Der unterste Punkt für alpha = 0 lässt sich also durch 450 - schriftgröße - 25 (= 401)angeben, der oberste für alpha = 1 durch schriftgröße + 25 (= 49).

Hier mal mein aktueller Quelltext zum Problem:

[code]
1) const int yb = (int)((450-tsize-25)-(alpha*(450-50-(2*tsize))));

2) visu[1].draw_rectangle(38, 450-tsize-23, 62, tsize+23, lblue, 1).
draw_rectangle(39, 450-tsize-24, 61, tsize+24, dblue, 1).draw_rectangle(40, 450-tsize-25, 60, yb, blue, 1);

3) if ((disp.button()) && (disp.mouse_x()>=img.width() + 38) && (disp.mouse_x()<=img.width() + 62) &&
(disp.mouse_y()>=tsize + 25) && (disp.mouse_y()<=450-tsize-25))
{
4) alpha = ((disp.mouse_y() -450 +25 +tsize) / ((50 +(2*tsize) -450)/100));
alpha/= 100;

5) if(alpha>0.999)
{
alpha = 0.999;
}
}
[/code]1) hier wird yb berechnet, welches die Höhe des Balkens angibt in Abhängigkeit von alpha, funzt wunderbar

2) da wird einfach nur der Balken gezeichnet an die entsprechenden Koordinaten

3) Sobald in dem Balken ein Mausklick registriert wird...

4) ...berechne das zugehörige alpha aus der y-Position des Klicks (bei dieser Formel liegt der Hund begraben, aktuell habe ich die obere Formel von yb genommen und nach alpha umgestellt und für yb die y-Mauskoordinate angenommen)

5) sollte alpha größer werden als 0,999 setze es au 0,999, soll einfach verhindern das Werte mit 1 angenommen werden können, da dann die Schärfeformel Müll rechnet ;)

Tja, so wie ich das im Moment so stehen habe, ergibt sich folgendes Problem, umso weiter ich den Balken nach oben schieben will, desto weiter eilt der Balken meiner Maus voraus. In den unteren Regionen bei alpha ca. 0,1 stimmt die Balkenposition mit der Mausposition überein. Umso größer das alpha wird, umso größer auch der Fehler. Hab leider keine Ahnung mehr woran das liegen kann. Irgend einen einfachen Offset kann ich nicht vergessen haben, da sonst über den gesamten Balkenverlauf der Fehler (Distanz y-Balkenposition zu y-Mausposition) immer gleich groß wäre. In meinem Fall jedoch nimmt er mit kleinerer y-Mauskoordinate zu...

Wäre schön wenn jmd. eine Idee liefer könnte, bin mit meinem Latein am Ende,hoffe ich konnte es ausreichend rüberbringen :)

mfg
kanonenfutter

redfalcon 26.09.2010 12:09

AW: [C++] Problem bei Denkaufgabe
 
Haben alpha und disp.mouse_y die selben Datentypen?

Ich würde mir zuerst mal Debug-Ausgaben für alpha und disp.mouse_y machen, dann sieht man in welchen Wertebereichen die Variablen auseinanderlaufen. Ich vermute, dass ein Offset mit sinkendem y-Wert zuviel draufgerechnet wird.
Den kompletten Quelltext kannst du nicht hochladen, oder?

kanonenfutter 26.09.2010 13:16

AW: [C++] Problem bei Denkaufgabe
 
Tja, also alpha ist ein double, disp.mouse_y() ist ein integer.

Kompletter Quelltext:

[code]
#include "CImg.h"
using namespace cimg_library;

int main()
{
CImg<int>img("leucht.jpg");
CImgList<double>visu(img, CImg<int>(100,450,1,3,0));
CImgDisplay disp(visu,"Test");

int pw, mw, neu, i, j, valR, valG, valB, avg = 0;
int tsize = 24;

const unsigned char white[] = {255,255,255};
const unsigned char blue[] = {0,0,255};
const unsigned char lblue[] = {0,0,192};
const unsigned char dblue[] = {0,0,128};

for (double alpha = 0.5; !disp.is_closed() && !disp.is_keyQ() && !disp.is_keyESC(); )
{
for(int x=1; x<img.width()-1; x++)
{
for(int y=1; y<img.height()-1; y++)
{
pw = img(x,y,0,0);
mw = 0;

for(i=-1; i<=1; i++)
{
for(j=-1; j<=1; j++)
{
mw += img(x+i, y+j, 0, 0);
}
}

mw /= 9;
neu = (int)((pw - (alpha*mw)) / (1.0-alpha));

if(neu > 255)
{
neu = 255;
}
else if(neu < 0)
{
neu = 0;
}
visu[0](x,y,0,0) = neu;

valR = visu[0](x,y,0,0); // Read the red component
valG = visu[0](x,y,0,1); // Read the green component
valB = visu[0](x,y,0,2); // Read the blue component (Z


avg = (int)((valR + valG + valB)/3); // Compute average pixel value.

visu[0](x,y,0,0) = visu[0](x,y,0,1) = visu[0](x,y,0,2) = avg; //Graubild

}
}

visu[1].fill(0).draw_text(25,5,"Alpha",white,0,1,tsize).
draw_text(35,450-tsize-5,"%.2f",white,0,1,tsize,alpha);
visu[0].draw_line(img.width()-1,0,img.width()-1,img.height(),white,1);

const int yb = (int)((450-tsize-25)-(alpha*(450-50-(2*tsize))));

visu[1].draw_rectangle(38, 450-tsize-23, 62, tsize+23, lblue, 1).
draw_rectangle(39, 450-tsize-24, 61, tsize+24, dblue, 1).draw_rectangle(40, 450-tsize-25, 60, yb, blue, 1);

if ((disp.button()) && (disp.mouse_x()>=img.width() + 38) && (disp.mouse_x()<=img.width() + 62) &&
(disp.mouse_y()>=tsize + 25) && (disp.mouse_y()<=450-tsize-25))
{
alpha = ((disp.mouse_y() -450 +25 +tsize) / ((50 +(2*tsize) -450)/100));
alpha/= 100;

if(alpha>0.999)
{
alpha = 0.999;
}
}

disp.resize(disp,false).display(visu).wait();
}
}
[/code]Kommentare zu jeder einzelnen Zeile spare ich mir mal ;)

mfg

redfalcon 26.09.2010 14:31

AW: [C++] Problem bei Denkaufgabe
 
So funktioniert es, ich weiss aber noch nicht ganz warum. Bei deiner Berechnung bekommt alpha zwar Werte, allerdings nur stark gerundete. In meiner Version kommen da viel genauere Werte raus. Mit sinkendem y-Wert wird der Unterschied dann immer gravierender, daher wohl die Verschiebung.

[code]
//Bei dir vermutlich anders:
//#define cimg_graphicsmagick_path 'D:\GraphicsMagick'
#include "CImg.h"
#include <iostream>
using namespace cimg_library;
using namespace std;

int main()
{
CImg<int>img("leucht.jpg");
CImgList<double>visu(img, CImg<int>(100,450,1,3,0));
CImgDisplay disp(visu,"Test");

int pw, mw, neu, i, j, valR, valG, valB, avg = 0;
int tsize = 24;
double upperOffset = tsize+25;
double lowerOffset = 450-tsize-25;
double offsetMod = 2;
double oldalpha = 0.0;

const unsigned char white[] = {255,255,255};
const unsigned char blue[] = {0,0,255};
const unsigned char lblue[] = {0,0,192};
const unsigned char dblue[] = {0,0,128};

for (double alpha = 0.5; !disp.is_closed() && !disp.is_keyQ() && !disp.is_keyESC(); )
{
for(int x=1; x<img.width()-1; x++)
{
for(int y=1; y<img.height()-1; y++)
{
pw = img(x,y,0,0);
mw = 0;

for(i=-1; i<=1; i++)
{
for(j=-1; j<=1; j++)
{
mw += img(x+i, y+j, 0, 0);
}
}

mw /= 9;
neu = (int)((pw - (alpha*mw)) / (1.0-alpha));

if(neu > 255)
{
neu = 255;
}
else if(neu < 0)
{
neu = 0;
}
visu[0](x,y,0,0) = neu;

valR = visu[0](x,y,0,0); // Read the red component
valG = visu[0](x,y,0,1); // Read the green component
valB = visu[0](x,y,0,2); // Read the blue component (Z


avg = (int)((valR + valG + valB)/3); // Compute average pixel value.

visu[0](x,y,0,0) = visu[0](x,y,0,1) = visu[0](x,y,0,2) = avg; //Graubild

}
}

visu[1].fill(0).draw_text(25,5,"Alpha",white,0,1,tsize).
draw_text(35,450-tsize-5,"%.2f",white,0,1,tsize,alpha);
visu[0].draw_line(img.width()-1,0,img.width()-1,img.height(),white,1);

const int yb = (int)((450-tsize-25)-(alpha*(450-50-(2*tsize))));

visu[1].draw_rectangle(38, 450-tsize-23, 62, tsize+23, lblue, 1).
draw_rectangle(39, 450-tsize-24, 61, tsize+24, dblue, 1).draw_rectangle(40, 450-tsize-25, 60, yb, blue, 1);

// cout << "Mouse: " << disp.mouse_y() << endl;

if ((disp.button()) && (disp.mouse_x()>=img.width() + 38) && (disp.mouse_x()<=img.width() + 62) &&
(disp.mouse_y()>=tsize + 25) && (disp.mouse_y()<=450-tsize-25))

{

alpha = ((disp.mouse_y() - lowerOffset) / ((offsetMod*upperOffset -450)/100));
oldalpha = ((disp.mouse_y() -450 +25 +tsize) / ((50 +(2*tsize) -450)/100));
alpha/= 100;
oldalpha /= 100;

if(alpha>=0.999)
{
alpha = 0.999;
}

if(oldalpha>=0.999)
{
oldalpha = 0.999;
}
cout << "alpha: " << alpha << endl;
cout << "oldalpha: " << oldalpha << endl;
}

disp.resize(disp,false).display(visu).wait();
}
}
[/code]

kanonenfutter 26.09.2010 14:46

AW: [C++] Problem bei Denkaufgabe
 
Hm, sehr einfach, dennoch genial :D

Also ich versteh zwar nicht warum, wenn ich den Offset in Variablen packe, das ganze besser funzt als wenn ichs später berechne, aber naja..

Dickes Danke erstmal ;)

kanonenfutter 26.09.2010 16:19

AW: [C++] Problem bei Denkaufgabe
 
Also das Teilprogramm läuft 1A, danke nochmal dafür ;)

Nun wollte ich die gleiche Idee des einstellbaren Wertes mittels Schieberegler bei einem anderen Teilprogramm verwenden. Dabei geht es um die Binarisierung eines Bildes, heißt die Darstellung des Bildes nur mithilfe von schwarzen oder weißen Pixeln. Von einem s/w-Bild werden dabei die Grauwerte jeden Pixels ausgelesen und dann mit einem Schwellwert verglichen. Liegt der Pixelwert darunter wird er auf 0, darüber auf 255 gesetzt. Diesen Schwellwert würde ich ebenfalls gern mit einem solchen Balken einstellen. Einzige Umstellung ist, dass der Wert nun nicht von 0 bis 1 sondern von 0 bis 255 läuft (integer).

Gut, eigentlich kein Problem, habe die Idee von oben genommen, etwas abgeändert und, naja, habe mal wieder ein problem... :(

Mal abgesehen davon das ich mal wieder noch nicht sicher bin wie ich den Wert über die y-Mauposition errechnen soll, habe ich das Problem, dass mein Balken nicht ordentlich gezeichnet wird. Meiner Meinung nach müsste die Formel im Code richtig sein, nur scheint mir das Programm dort einige Klammern zu unterschlagen, und zeigt somit den Balken immer bei Position 0 an (für gwin = Grauwertschwelle = 0 bis 254), ab 255 wird der balken voll bis nach oben gezeichnet. Heißt für die Berechnung von 1 bis 254 läuft irgendwas schief...

Hier direkt mal der aktuelle Quelltext dazu:

[code]
#include "CImg.h"
using namespace cimg_library;

int main()
{
CImg<int>img("lena.jpg");
CImg<int>gimg(img.width(), img.height(), 1, 3, 0);
CImg<int>bimg(img.width(), img.height(), 1, 3, 0);
CImgList<double>visu(bimg, CImg<int>(100,600,1,3,0));
CImgDisplay disp(visu,"Test");
//disp.resize(disp.screen_width()-20, 600*(disp.screen_width()-20)/1700, false);

int valR, valG, valB = 0;
double avg = 0.0;
int tsize = 24;
double upperOffset = tsize+25;
double lowerOffset = 600-tsize-25;
double offsetMod = 2;

const unsigned char white[] = {255,255,255};
const unsigned char blue[] = {0,0,255};
const unsigned char lblue[] = {0,0,192};
const unsigned char dblue[] = {0,0,128};

for (int gwin = 128; !disp.is_closed() && !disp.is_keyQ() && !disp.is_keyESC(); )
{
for(int x = 0; x < img.width(); x++) //Schleife über x,y und Farbkanal
{
for(int y = 0; y < img.height(); y++)
{
valR = img(x,y,0,0); // Read the red component
valG = img(x,y,0,1); // Read the green component
valB = img(x,y,0,2); // Read the blue component (Z-coordinate omitted here).
avg = (valR + valG + valB)/3; // Compute average pixel value.

gimg(x,y,0,0) = gimg(x,y,0,1) = gimg(x,y,0,2) = avg; //Graubild

if(avg>=gwin) //Binarisierung
{
visu[0](x,y,0) = visu[0](x,y,1) = visu[0](x,y,2) = 255;
}
else visu[0](x,y,0) = visu[0](x,y,1) = visu[0](x,y,2) = 0;
}
}

visu[1].fill(0).draw_text(18,5,"Grenze",white,0,1,tsize).
draw_text(36,600-tsize-5,"%d",white,0,1,tsize,gwin);
visu[0].draw_line(img.width()-1,0,img.width()-1,img.height(),white,1);

double pro = gwin / 255;
const int yb = (int)(lowerOffset-(pro*(600-offsetMod*upperOffset))); // ???

visu[1].draw_rectangle(38, 600-tsize-23, 62, tsize+23, lblue, 1).
draw_rectangle(39, 600-tsize-24, 61, tsize+24, dblue, 1).draw_rectangle(40, 600-tsize-25, 60, yb, blue, 1);

if ((disp.button()) && (disp.mouse_x()>=img.width() + 38) && (disp.mouse_x()<=img.width() + 62) &&
(disp.mouse_y()>=tsize + 25) && (disp.mouse_y()<=600-tsize-25))
{
gwin = (int)(600 -disp.mouse_y() -(tsize+25)); // ???

if(gwin>255)
{
gwin = 255;
}
}

disp.resize(disp,false).display(visu).wait();
}
}
[/code]

Und hier noch ein Bildchen zur Veranschaulichung:

[IMG]http://www.tweakpc.de/forum/members/kanonenfutter-albums-test-picture1642-c-bv.jpg[/IMG]

Bin nochmal am tüfteln, wenn jmd eine Idee hat, nur her damit ;)

mfg

kanonenfutter 27.09.2010 11:50

AW: [C++] Problem bei Denkaufgabe
 
Ok hat sich bereits erledigt, hier dann mal die geänderten Programmzeilen aus dem Code oben, so dass es funzt:

[code]
const int yb = (int)(LowerOffset-((gwin/255)*(gimg.height()-OffsetMod*UpperOffset)));

visu[1].draw_rectangle(38, gimg.height()-tsize-23, 62, tsize+23, lblue, 1).
draw_rectangle(39, gimg.height()-tsize-24, 61, tsize+24, dblue, 1).draw_rectangle(40, gimg.height()-tsize-25, 60, yb, blue, 1);

if ((disp.button()) && (disp.mouse_x()>=gimg.width() + 38) && (disp.mouse_x()<=gimg.width() + 62) &&
(disp.mouse_y()>=tsize + 25) && (disp.mouse_y()<=gimg.height()-tsize-25))
{
gwin = 255 * ((disp.mouse_y() - LowerOffset) / (OffsetMod*UpperOffset -gimg.height()));

if(gwin>255)
{
gwin = 255;
}
}
[/code]

PS: gwin war zuvor ein int, dadurch konnte die Berechnung gwin/255 nicht durchgeführt werden und war somit immer 0, außer für gwin = 255, da war es dann eben 1. Also den auf double und dann läufts schon besser ;)

mfg


Alle Zeitangaben in WEZ +1. Es ist jetzt 08:37 Uhr.

Powered by vBulletin® Version 3.8.10 (Deutsch)
Copyright ©2000 - 2024, vBulletin Solutions, Inc.
SEO by vBSEO 3.5.2 ©2010, Crawlability, Inc.