Opencv c++ Bild mit Maske kopieren



  • Da hast du aber Glück, dass ich deinen Edit zufällig noch gesehen hab.

    Was willst du denn da machen?
    C soll A sein wenn B größer ist als A und ansonsten B?
    also sowas wie C=min(A,B)?
    Was soll der operator> denn da von A und B vergleichen? Die Anzahl Zeilen oder Spalten? Die Summe aller Elemente?



  • Hallo Dobi,

    ich habe eine Internet-Seite gefunden auf der Blend-Modies von Photoshop erklärt sind und wollte manche übernehmen.

    #define ChannelBlend_Normal(A,B)     ((uint8)(A))
    #define ChannelBlend_Lighten(A,B)    ((uint8)((B > A) ? B:A))
    #define ChannelBlend_Darken(A,B)     ((uint8)((B > A) ? A:B))
    #define ChannelBlend_Multiply(A,B)   ((uint8)((A * B) / 255))
    #define ChannelBlend_Average(A,B)    ((uint8)((A + B) / 2))
    #define ChannelBlend_Add(A,B)        ((uint8)(min(255, (A + B))))
    #define ChannelBlend_Subtract(A,B)   ((uint8)((A + B < 255) ? 0:(A + B - 255)))
    #define ChannelBlend_Difference(A,B) ((uint8)(abs(A - B)))
    #define ChannelBlend_Negation(A,B)   ((uint8)(255 - abs(255 - A - B)))
    #define ChannelBlend_Screen(A,B)     ((uint8)(255 - (((255 - A) * (255 - B)) >> 8)))
    #define ChannelBlend_Exclusion(A,B)  ((uint8)(A + B - 2 * A * B / 255))
    #define ChannelBlend_Overlay(A,B)    ((uint8)((B < 128) ? (2 * A * B / 255):(255 - 2 * (255 - A) * (255 - B) / 255)))
    #define ChannelBlend_SoftLight(A,B)  ((uint8)((B < 128)?(2*((A>>1)+64))*((float)B/255):(255-(2*(255-((A>>1)+64))*(float)(255-B)/255))))
    #define ChannelBlend_HardLight(A,B)  (ChannelBlend_Overlay(B,A))
    #define ChannelBlend_ColorDodge(A,B) ((uint8)((B == 255) ? B:min(255, ((A << 8 ) / (255 - B)))))
    #define ChannelBlend_ColorBurn(A,B)  ((uint8)((B == 0) ? B:max(0, (255 - ((255 - A) << 8 ) / B))))
    #define ChannelBlend_LinearDodge(A,B)(ChannelBlend_Add(A,B))
    #define ChannelBlend_LinearBurn(A,B) (ChannelBlend_Subtract(A,B))
    #define ChannelBlend_LinearLight(A,B)((uint8)(B < 128)?ChannelBlend_LinearBurn(A,(2 * B)):ChannelBlend_LinearDodge(A,(2 * (B - 128))))
    #define ChannelBlend_VividLight(A,B) ((uint8)(B < 128)?ChannelBlend_ColorBurn(A,(2 * B)):ChannelBlend_ColorDodge(A,(2 * (B - 128))))
    #define ChannelBlend_PinLight(A,B)   ((uint8)(B < 128)?ChannelBlend_Darken(A,(2 * B)):ChannelBlend_Lighten(A,(2 * (B - 128))))
    #define ChannelBlend_HardMix(A,B)    ((uint8)((ChannelBlend_VividLight(A,B) < 128) ? 0:255))
    #define ChannelBlend_Reflect(A,B)    ((uint8)((B == 255) ? B:min(255, (A * A / (255 - B)))))
    #define ChannelBlend_Glow(A,B)       (ChannelBlend_Reflect(B,A))
    #define ChannelBlend_Phoenix(A,B)    ((uint8)(min(A,B) - max(A,B) + 255))
    #define ChannelBlend_Alpha(A,B,O)    ((uint8)(O * A + (1 - O) * B))
    #define ChannelBlend_AlphaF(A,B,F,O) (ChannelBlend_Alpha(F(A,B),A,O))
    

    Nur Funktionieren die mit True or False Operator "?" nicht 😞



  • Da geht es um Skalare (Pixelwerte). Was sind in deinem code

    Mat C= ((B > A) ? A:B);
    

    A und B denn für Typen? cv::Mat?



  • Hallo,

    genau A und B sind Mat Typen.

    Mat A(imread("Bild1.jpg", CV_LOAD_IMAGE_COLOR));
    Mat B(imread("Bild2.jpg", CV_LOAD_IMAGE_COLOR));

    Gruß



  • Gut, also machst du da jetzt das:

    Mat A(imread("Bild1.jpg", CV_LOAD_IMAGE_COLOR));
    Mat B(imread("Bild2.jpg", CV_LOAD_IMAGE_COLOR));
    Mat C= ((B > A) ? A:B);
    

    Und das ist das gleiche wie das:

    Mat A(imread("Bild1.jpg", CV_LOAD_IMAGE_COLOR));
    Mat B(imread("Bild2.jpg", CV_LOAD_IMAGE_COLOR));
    Mat C = std::min(A, B);
    

    Und das ist das gleiche wie das:

    Mat A(imread("Bild1.jpg", CV_LOAD_IMAGE_COLOR));
    Mat B(imread("Bild2.jpg", CV_LOAD_IMAGE_COLOR));
    Mat C;
    if (B > A)
    {
        C = A;
    }
    else
    {
        C = B;
    }
    

    Du willst das aber pixelweise haben, jedoch verrätst du deinem Compiler das nicht. 😉



  • Hier ist mein Code

    #include "opencv2/imgproc/imgproc.hpp"
    #include "opencv2/highgui/highgui.hpp"
    #include <stdio.h>
    #include <iostream>
    
    using namespace std;
    using namespace cv;
    char window_name[] = "Mein Fenster";
    
     int main( int argc, char** argv )
     {
    
    Mat A(imread("Bild1.jpg", CV_LOAD_IMAGE_COLOR));
    Mat B(imread("Bild2.jpg", CV_LOAD_IMAGE_COLOR));
    
    Mat C;
    if (B > A)
    {
        C = A;
    }
    else
    {
        C = B;
    }
    
    imshow( window_name, C );
    waitKey(0);
    
    return 0;
    }
    

    Wenn ich versuche es zu kompilieren bekomme ich immer folgende Fehlermeldung :

    mul.cpp: In Funktion »int main(int, char**)«:
    mul.cpp:29:10: Fehler: »cv::operator>(const cv::Mat&, const cv::Mat&)(((const cv::Mat)(& A)))« konnte nicht von »cv::MatExpr« nach »bool« umgewandelt werden



  • Ja, schon klar. Was soll der Compiler beispielsweise auch mit dieser Zeile anfangen?

    if (B > A)
    

    Wann ist eine Matrix größer als eine andere?

    Was du willst, sind pixelweise Vergleiche. Die machst du aber gar nicht.



  • Na gut, will ich mal nicht so sein. 😉

    #include <opencv2/opencv.hpp>
    using namespace cv;
    int main()
    {
    	Mat img_a(imread("1.png"));
    	Mat img_b(imread("2.png"));
    
    	// Beide Bilder sollten gleich gross sein.
    	assert(img_a.size() == img_b.size());
    
    	// Beide Bilder sollten vom gleichen Typ sein.
    	assert(img_a.type() == img_b.type());
    
    	// darken blend
    	Mat img_c(cv::min(img_a, img_b));
    
    	// Speichern
    	imwrite("out.png", img_c);
    }
    

    Für dein Channel-Blend-Darken bekommt es also noch so hin. Jenachdem, was du vor hast, musst du aber eh früher oder später lernen, wie man auf die einzelnen Pixel zugreift. Hier der gleiche Algorithmus nur per Hand:

    #include <opencv2/opencv.hpp>
    using namespace cv;
    int main()
    {
    	Mat img_a(imread("1.png", CV_LOAD_IMAGE_GRAYSCALE));
    	Mat img_b(imread("2.png", CV_LOAD_IMAGE_GRAYSCALE));
    
    	// Beide Bilder sollten gleich gross sein.
    	assert(img_a.size() == img_b.size());
    
    	// Beide Bilder sollten vom gleichen Typ sein.
    	assert(img_a.type() == img_b.type());
    
    	// Zielbild anlegen
    	Mat img_c(img_a.size(), img_a.type());
    
    	// darken blend
    	typedef unsigned char byte;
    	for (int y = 0; y < img_c.rows; ++y)
    	{
    		for (int x = 0; x < img_c.cols; ++x)
    		{
    			byte a = img_a.at<byte>(y, x);
    			byte b = img_b.at<byte>(y, x);
    			img_c.at<byte>(y, x) = b > a ? a : b; // img_c.at<byte>(y, x) = std::min(a, b)
    		}
    	}	
    
    	// Speichern
    	imwrite("out.png", img_c);
    }
    

    Hier die Bilder dazu: http://daiw.de/share/index.php?dir=Forum%2F2013-05-03_cpp%2F

    Was hast du eigentlich generell vor? Ich frage, weil das, was du da tust, hat ja erstmal wenig mit Computer Vision zu tun.



  • Hallo Dobi,

    vielen Dank für deinen Post, schon habe ich wieder was gelernt, ich versuche generell immer noch meine Filter die ich bisher in Imagemagick vorliegen habe mit opencv zu realisieren im Moment laufen die Filter die ich fertig habe mit ca. 0.08 ms bis 0.5ms. Imagemagick im Gegensatz dazu mit 1.5s bis 3s und das obwohl Imagemgick mit mehreren CPUś arbeitet.

    Gruß



  • Das ist interessant. Normalerweise würde man ja erwarten, dass Imagemagick schon ziemlich durchoptimiert ist. Kann es sein, dass du bei deiner Version nur die Filterei an sich mit deiner Stopuhr misst und bei Imagemagick alles, also Programm starten, Bilder laden, Filtern und Ergebnis speichern?



  • Ich mache mit Imagemagick die selben Arbeitsschritte wie mit opencv, sprich Bild laden, Maske laden, Maske an Bildgröße anpassen, Maske mit Bild verrechnen und Bild anschließend speichern.

    Ich messe die Zeit mit dem "time" Befehl

    loonix@ubuntu:~/opencv-2.4.5/test$ time ./mul

    real 0m0.041s
    user 0m0.036s
    sys 0m0.004s

    Ich habe mal deinen zweiten Programmcode kopiert und bei mir eingefügt.
    Wenn ich den Modus der beiden Bilder von GRAYSCALE zu COLOR ändere und das ganz ausführe, wird zwar die Ausgabedatei erstellt aber das Bild ist nur zu einem drittel vorhanden der Rest ist Schwarz. Wo dran kann das liegen?

    Gruß



  • Du misst also die Zeit, die der Programmstart usw. dauert, mit. Das ist ungefähr so als wollten wir beide gucken, wer von uns beiden im 100m-Sprint schneller ist, aber die Zeitmessung incl. Zug-Anreise zum Sportplatz, umziehen, aufwärmen, hinterher duschen und wieder nach Hause fahren messen. 😉

    Ja, der von vom gepostete Code funktioniert nur für Bilder vom TYP CV_8UC1, weil ich

    cv::Mat::at<unsigned char>(y, x)
    

    benutze. Bei Farbbildern (meistens CV_8UC3) ist jeder Pixel aber 3 Byte groß. Du brauchst also entweder noch eine weitere Verschachtelung in den Schleifen in der Art von

    for (int c = 0; c < img_c.channels(); ++c)
    

    durch die Kanäle doppelst. Oder du liest die Pixel als cv::vec3b statt als unsigned char aus.

    Schau dir mal die beiden Tutorials hier an. Da wird erklärt, wie Bilder im Speicher liegen usw:
    Mat - The Basic Image Container
    How to scan images, lookup tables and time measurement with OpenCV


  • Mod

    Dobi schrieb:

    Du misst also die Zeit, die der Programmstart usw. dauert, mit. Das ist ungefähr so als wollten wir beide gucken, wer von uns beiden im 100m-Sprint schneller ist, aber die Zeitmessung incl. Zug-Anreise zum Sportplatz, umziehen, aufwärmen, hinterher duschen und wieder nach Hause fahren messen. 😉

    real world metapher par excellence 👍 😃



  • Guter Vergleich ;-).

    okay habe es hinbekommen :-).

    Danke



  • 🙂



  • Moin,

    ich habe mal wieder ein kleines Problem und zwar... in Gimp kann ich als Ebenen Modus "Division" auswählen.

    Die Formel dazu findet man auf http://docs.gimp.org/de/gimp-concepts-layer-modes.html

    E = (256 * I) / (M + 1)

    Mein C++ Code durchläuft jeden Pixel und Kanal und führt die Formel aus.
    Nur sieht mein Bild welches ich erzeuge bei weitem nicht so aus wie das Ergebnis welches Gimp mir ausgibt.

    Mein Bild hat sehr viele bunte "pixelfehler". Ich kann gerne auch mal mein Bild hochladen vielleicht hilft das ja.

    #include "opencv2/imgproc/imgproc.hpp"
    #include "opencv2/highgui/highgui.hpp"
    #include <stdio.h>
    #include <iostream>
    
    using namespace std;
    using namespace cv;
    char window_name1[] = "Fenster 1";
    
    int main( int argc, char** argv )
     {
    
        Mat src(imread(argv[1], CV_LOAD_IMAGE_COLOR));
        cv::dilate(src,dest,Mat(Size(3, 3), CV_8UC1));
    
        Mat img_c(src.size(), src.type());
        typedef unsigned char byte;
    
        for (int y = 0; y < dest.rows; ++y)
        {
            for (int x = 0; x < dest.cols; ++x)
            {
    		for(int c = 0; c < dest.channels(); c++)
                     {
     		   byte a = src.at<Vec3b>(y, x)[c];
                       byte b = dest.at<Vec3b>(y, x)[c];	
                       img_c.at<Vec3b>(y,x)[c] = ((256*a)/(b+1));
    		 }
            }
        }
    
        imshow( window_name1, img_c );
        waitKey(0);
    
    return 0;
    }
    


  • Loonix schrieb:

    byte a = src.at<Vec3b>(y, x)[c];
                       byte b = dest.at<Vec3b>(y, x)[c];	
                       img_c.at<Vec3b>(y,x)[c] = ((256*a)/(b+1));
    

    Du multiplizierst ein Byte mit 256?



  • Schande über mein Haupt, habe den Fehler gefunden danke.



  • Ich möchte ebenfalls einen Bildausschnitt in ein anderes Bild kopieren. Zum Beispiel ein Bild mit einem Fussballer in ein Bild mit einem Fussballstadion. Ich möchte also den Fussballer herauskopieren und in ein anderes Bild einsetzen. Es soll aber nachher so aussehen als ob er in dieses Bild gehört. WIe kann ich das anstellen. Muss ich wirklich erst über verschiedene Algorithmen gehen wie: Kontrast, Cannyfilterung nd Kantenerkennung oder geht dies auch anders. Am besten möchte ich das über einen Gui machen, sodass Benutzer dies auch ausführen könnten. DIe Gui ist aber ertsmal hinten angestellt.


  • Mod

    meinst du sowas wie poisson blending?

    http://eric-yuan.me/poisson-blending/


Anmelden zum Antworten