Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

Algorytm blit - 'wklejanie' z offsetem

Ostatnio zmodyfikowano 2014-09-27 22:29
Autor Wiadomość
kubawal
Temat założony przez niniejszego użytkownika
Algorytm blit - 'wklejanie' z offsetem
» 2014-09-26 21:15:34
Witam. Mam funkcję blit(), która 'wkleja' fragment obrazu w lewym górnym rogu innego.
Potrzebuję jednak zaimplementować możliwość wklejania w dowolnym miejscu obrazu docelowego.
I tu pojawia się problem: o ile jest to łatwe przy adresowaniu obraz[x][y], to przy adrsowaniu ciągłym (obraz[y * width + x]) nie mogę tego zaprogramować. Na dodatek każdy piksel zajmuje cztery miejsca w vectorze (R, G, B i A), czyli:
C/C++
Rxy = obraz[ y * width + x ];
Gxy = obraz[ y * width + x + 1 ];
Bxy = obraz[ y * width + x + 2 ];
Axy = obraz[ y * width + x + 3 ];

Oto moja wersja z wklejaniem w górnym lewym rogu:
C/C++
unsigned blit( const Img & src, Img & dest, const Rect & srcreg )
{
    if( dest.w < srcreg.rd.x - srcreg.lt.x )
         return 0;
   
    if( dest.h < srcreg.rd.y - srcreg.lt.y )
         return 0;
   
    if( dest.px.size() != dest.w * dest.h * 4 )
         return 0; // złe informacje o obrazie
   
   
    unsigned n = 0;
   
    for( int i =( reg.lt.y * src.w + reg.lt.x ) * 4; i < src.px.size(); i += 4 )
    {
        unsigned y =( i / 4 ) / src.w;
        unsigned x =( i / 4 ) % src.w;
       
        if( isInRect( Point( x, y ), reg ) )
        {
            dest.px[ n + 0 ] = src.px[ i + 0 ];
            dest.px[ n + 1 ] = src.px[ i + 1 ];
            dest.px[ n + 2 ] = src.px[ i + 2 ];
            dest.px[ n + 3 ] = src.px[ i + 3 ];
            n += 4;
        }
       
        if( y > reg.rd.y )
             break;
       
    }
    return n / 4;
}

struct Img
{
    vector < unsigned char > px;
    unsigned w, h;
   
   
    //...
};

struct Point
{
    unsigned x, y;
   
    //...
};

struct Rect
{
    Point lt, rd;
};

Jeśli macie jakiś pomysł, to piszcie.
P-117621
stryku
» 2014-09-26 22:02:59
o takie coś chodziło?
C/C++
unsigned blit( const Img & src, Img & dest, const Rect & srcreg, const Point & start ) // poczatkowy x i y
{
    if( dest.w < srcreg.rd.x - srcreg.lt.x )
         return 0;
   
    if( dest.h < srcreg.rd.y - srcreg.lt.y )
         return 0;
   
    if( dest.px.size() != dest.w * dest.h * 4 )
         return 0; // złe informacje o obrazie
   
   
    unsigned n = start.y * dst.w + start.x; //tu dodałem
   
    for( int i =( reg.lt.y * src.w + reg.lt.x ) * 4; i < src.px.size(); i += 4 )
    {
        unsigned y =( i / 4 ) / src.w;
        unsigned x =( i / 4 ) % src.w;
       
        if( isInRect( Point( x, y ), reg ) )
        {
            dest.px[ n + 0 ] = src.px[ i + 0 ];
            dest.px[ n + 1 ] = src.px[ i + 1 ];
            dest.px[ n + 2 ] = src.px[ i + 2 ];
            dest.px[ n + 3 ] = src.px[ i + 3 ];
            n += 4;
        }
       
        if( y > reg.rd.y )
             break;
       
    }
    return n / 4;
}
P-117630
kubawal
Temat założony przez niniejszego użytkownika
» 2014-09-26 22:24:03
Nie, bo układ rzędów i kolumn źródła nie bedzie zachowany, np fragment 1 linijki wklei się w 2 albo na odwrót.
Takie proste to nie jest :)
P-117633
pekfos
» 2014-09-26 22:36:31
Takie proste to nie jest :)
Jest. Główny problem to połapać się w tym, co już napisałeś. Zrób sobie funkcję wstawiającą piksel w określony współrzędnymi punkt na obrazie. Może być tylko na kartce, jak sam pozbierasz myśli to już nie będzie potrzebna.
P-117637
stryku
» 2014-09-26 22:45:20
C/C++
unsigned blit( const Img & src, Img & dest, const Rect & srcreg, const Point & start ) // poczatkowy x i y
{
    if( dest.w < srcreg.rd.x - srcreg.lt.x )
         return 0;
   
    if( dest.h < srcreg.rd.y - srcreg.lt.y )
         return 0;
   
    if( dest.px.size() != dest.w * dest.h * 4 )
         return 0; // złe informacje o obrazie
   
   
    unsigned n = start.y * dst.w + start.x; //tu dodałem
   
    for( int y = 0; y < 4 * src.h; y += 4 )
    {
        for( int x = 0; x < 4 * src.w; x += 4 )
        {
            if( isInRect( Point( x, y ), reg ) ) // tu nie zmieniłem
            {
                int tmp = n + y * src.w + x;
               
                dest.px[ tmp + 0 ] = src.px[ tmp + 0 ];
                dest.px[ tmp + 1 ] = src.px[ tmp + 1 ];
                dest.px[ tmp + 2 ] = src.px[ tmp + 2 ];
                dest.px[ tmp + 3 ] = src.px[ tmp + 3 ];
               
            }
           
            if( y > reg.rd.y )
                 break;
           
        }
    }
   
    return n / 4; //tu chyba chcesz src.px.size()*4
}
To? :d
P-117639
kubawal
Temat założony przez niniejszego użytkownika
» 2014-09-27 14:14:21
Ja też coś pokodziłem i wyszło mi coś takiego:
C/C++
struct Img
{
    //...
    Color getPixel( unsigned x, unsigned y ) const { unsigned n = y * w + x;
        return Color( px[ n ], px[ n + 1 ], px[ n + 2 ], px[ n + 3 ] ); }
   
    void setPixel( unsigned x, unsigned y, Color c ) { unsigned n = y * w + x;
        px[ n ] = c.r; px[ n + 1 ] = c.g; px[ n + 2 ] = c.b; px[ n + 3 ] = c.a; }
}
//...
unsigned blit( const Img & src, Img & dest, const Rect & srcreg, Point destPoint = Point() )
{
    if( dest.w < srcreg.rd.x - srcreg.lt.x + destPoint.x )
         return 0;
   
    if( dest.h < srcreg.rd.y - srcreg.lt.y + destPoint.y )
         return 0;
   
    unsigned dx = destPoint.x, dy = destPoint.y; // współrzędne aktualnego piksela celu
    for( int i =( srcreg.lt.y * src.w + srcreg.lt.x ) * 4; i < src.px.size(); i += 4 )
    {
        // współrzedne piksela źródła       
        unsigned y =( i / 4 ) / src.w;
        unsigned x =( i / 4 ) % src.w;
       
        if( isInRect( Point( x, y ), srcreg ) )
        {
            dest.setPixel( dx, dy, src.getPixel( x, y ) );
           
            if( dx == srcreg.rd.x - srcreg.lt.x + destPoint.x - 1 )
            {
                dx = 0;
                dy++;
               
                if( dy == srcreg.rd.y - srcreg.lt.y + destPoint.y )
                     break;
               
            }
            else
                 dx++;
           
        }
    }
   
    return 1;
}

Jednak wychodzą z tego randomowe pikselki, których jest tym więcej, im więcej pikseli funkcja ma skopoiwać :(
P-117666
pekfos
» 2014-09-27 15:23:55
Złe n w funkcjach pomocniczych.
P-117669
kubawal
Temat założony przez niniejszego użytkownika
» 2014-09-27 20:30:53
Teraz wychodzą randomowe kreski (to już lepiej niż pikselki ;D ). Dobry wynik jest tylko w wypadku wklejania w punkcie (0, 0).
Wiem, że nie jest to błąd przejściowy, za każdym  uruchomieniem programu daje dokładnie taki sam wynik.
P-117688
« 1 » 2
  Strona 1 z 2 Następna strona