为什么这种缩减算法会产生伪像?

时间:2016-10-12 15:41:16

标签: c++ c++11 cocos2d-x cocos2d-x-3.0 cocos2d-x-3.x

我有一个缩放算法,可以将图像缩放到正确的大小,但会在图像的右半部分产生伪像(轻微的图像损坏)。由于我没有经验使用指针,我怀疑我可能在我的指针算术上犯了错误!

在OSX上运行项目: 1.从https://www.dropbox.com/s/myme1z1mkxjwyjf/artifact.zip?dl=0

下载
  1. 打开proj.ios

  2. 中的xcodeproj文件
  3. 所有相关的代码都在HelloWorldScene.cpp中

  4. 在函数test()中,您可以注释掉/取消注释我们想要测试的方法。:

    void HelloWorld::test(){
        testCopy(); //In this case the image appears as expected. (a simple copy)
    //    testScale(); //In this case there are strange artifacts on the right tip of the arrow.
    }
    

    测试副本,是我尝试只是复制缓冲区的内容而不做任何坏事,如内存损坏,泄漏等......屏幕上显示的图像看起来不错!

    void HelloWorld::testCopy(){
    std::string infile = _imageName;
    
    Image* img = new Image();
    img->initWithImageFile(infile);
    auto odata = img->getData();
    
    Image* copy = new Image();
    
    int components = 4;
    auto finalDataLen = img->getDataLen();
    auto finalData = static_cast<unsigned char*>(malloc(finalDataLen));
    
    for (int i = 0; i<img->getWidth(); i++) {
        for (int j = 0; j<img->getHeight(); j++) {
            unsigned char *pixel = odata + (i + j * img->getWidth()) * components;
    
            unsigned char *fpixel = finalData + (i + j * img->getWidth()) * components;
            fpixel[0] = pixel[0];
            fpixel[1] = pixel[1];
            fpixel[2] = pixel[2];
            fpixel[3] = pixel[3];
        }
    }
    copy->initWithRawData(finalData, finalDataLen, img->getWidth(), img->getHeight(), 8);
    Texture2D* tk = new Texture2D();
    tk->initWithImage(copy);
    
    Sprite* foo = Sprite::createWithTexture(tk);
    foo->setPosition(Director::getInstance()->getVisibleSize().width/2,Director::getInstance()->getVisibleSize().height/2);
    foo->setScale(0.8);
    this->addChild(foo);
    
    delete img;
    delete copy;
    return;
    

    }

    现在注释掉testCopy();并取消注释testScale();在这种情况下,图像会出现,但图像的右侧有一些损坏!

    void HelloWorld::testScale(){
        std::string infile = _imageName;
    
        Image* img = new Image();
        img->initWithImageFile(infile);
        Image* scl = new Image();
        scaleImage(img, scl, 0.8);
    
        Texture2D* tk = new Texture2D(); //Texture is needed as long as the sprite exists, so we aren't deleting it.
        tk->initWithImage(scl);
        Sprite* foo = Sprite::createWithTexture(tk);
        foo->setPosition(Director::getInstance()->getVisibleSize().width/2,Director::getInstance()->getVisibleSize().height/2);
        this->addChild(foo);
    
        delete img;
        delete scl;
    
        return;
    }
    
    void HelloWorld::scaleImage(Image* original,Image* scaledImage,const float& scale){
        int width = scale*original->getWidth();
        int height = scale*original->getHeight();
    
        int x=4;
    
        unsigned char* data = original->getData();
    
        auto dataLen = width * height * x * sizeof(unsigned char);
        auto data2 = static_cast<unsigned char*>(malloc(dataLen));
    
        //sprshrink seems to be the problem method.
        sprshrink(data2, width, height, data, original->getWidth(), original->getHeight());
        scaledImage->initWithRawData(data2, dataLen, width, height, 8);
    }
    
    //Why does this method produce artifcats ?
    void HelloWorld::sprshrink(unsigned char *dest, int dwidth, int dheight, unsigned char *src, int swidth, int sheight){
        int x, y;
        int i, ii;
        float red, green, blue, alpha;
        float xfrag, yfrag, xfrag2, yfrag2;
        float xt, yt, dx, dy;
        int xi, yi;
    
    
        dx = ((float)swidth)/dwidth;
        dy = ((float)sheight)/dheight;
    
        for(yt= 0, y=0;y<dheight;y++, yt += dy)
        {
            yfrag = (float) ceil(yt) - yt;
            if(yfrag == 0)
                yfrag = 1;
            yfrag2 = yt+dy - (float) floor(yt + dy);
            if(yfrag2 == 0 && dy != 1.0f)
                yfrag2 = 1;
    
            for(xt = 0, x=0;x<dwidth;x++, xt+= dx)
            {
                xi = (int) xt;
                yi = (int) yt;
                xfrag = (float) ceil(xt) - xt;
                if(xfrag == 0)
                    xfrag = 1;
                xfrag2 = xt+dx - (float) floor(xt+dx);
                if(xfrag2 == 0 && dx != 1.0f)
                    xfrag2 = 1;
                red = xfrag * yfrag * src[(yi*swidth+xi)*4];
                green =  xfrag * yfrag * src[(yi*swidth+xi)*4+1];
                blue =   xfrag * yfrag * src[(yi*swidth+xi)*4+2];
                alpha =  xfrag * yfrag * src[(yi*swidth+xi)*4+3];
    
                for(i=0; xi + i + 1 < xt+dx-1; i++)
                {
                    red += yfrag * src[(yi*swidth+xi+i+1)*4];
                    green += yfrag * src[(yi*swidth+xi+i+1)*4+1];
                    blue += yfrag * src[(yi*swidth+xi+i+1)*4+2];
                    alpha += yfrag * src[(yi*swidth+xi+i+1)*4+3];
                }
    
                red += xfrag2 * yfrag * src[(yi*swidth+xi+i+1)*4];
                green += xfrag2 * yfrag * src[(yi*swidth+xi+i+1)*4+1];
                blue += xfrag2 * yfrag * src[(yi*swidth+xi+i+1)*4+2];
                alpha += xfrag2 * yfrag * src[(yi*swidth+xi+i+1)*4+3];
                for(i=0; yi+i+1 < yt +dy-1 && yi + i+1 < sheight;i++)
                {
                    red += xfrag * src[((yi+i+1)*swidth+xi)*4];
                    green += xfrag * src[((yi+i+1)*swidth+xi)*4+1];
                    blue += xfrag * src[((yi+i+1)*swidth+xi)*4+2];
                    alpha += xfrag * src[((yi+i+1)*swidth+xi)*4+3];
    
                    for (ii = 0; xi + ii + 1 < xt + dx - 1 && xi + ii + 1 < swidth; ii++)
                    {
                        red += src[((yi+i+1)*swidth+xi+ii+1)*4];
                        green += src[((yi+i+1)*swidth+xi+ii+1)*4+1];
                        blue += src[((yi+i+1)*swidth+xi+ii+1)*4+2];
                        alpha += src[((yi+i+1)*swidth+xi+ii+1)*4+3];
                    }
    
                    red += xfrag2 * src[((yi+i+1)*swidth+xi+ii+1)*4];
                    green += xfrag2 * src[((yi+i+1)*swidth+xi+ii+1)*4+1];
                    blue += xfrag2 * src[((yi+i+1)*swidth+xi+ii+1)*4+2];
                    alpha += xfrag2 * src[((yi+i+1)*swidth+xi+ii+1)*4+3];
                }
    
                if (yi + i + 1 < sheight)
                {
                    red += xfrag * yfrag2 * src[((yi + i + 1)*swidth + xi) * 4];
                    green += xfrag * yfrag2 * src[((yi + i + 1)*swidth + xi) * 4 + 1];
                    blue += xfrag * yfrag2 * src[((yi + i + 1)*swidth + xi) * 4 + 2];
                    alpha += xfrag * yfrag2 * src[((yi + i + 1)*swidth + xi) * 4 + 3];
    
                    for (ii = 0; xi + ii + 1 < xt + dx - 1 && xi + ii + 1 < swidth; ii++)
                    {
                        red += yfrag2 * src[((yi + i + 1)*swidth + xi + ii + 1) * 4];
                        green += yfrag2 * src[((yi + i + 1)*swidth + xi + ii + 1) * 4 + 1];
                        blue += yfrag2 * src[((yi + i + 1)*swidth + xi + ii + 1) * 4 + 2];
                        alpha += yfrag2 * src[((yi + i + 1)*swidth + xi + ii + 1) * 4 + 3];
                    }
                }
    
                if (yi + i + 1 < sheight && x + xi + 1 < swidth)
                {
                    red += xfrag2 * yfrag2 * src[((yi + i + 1)*swidth + xi + ii + 1) * 4];
                    green += xfrag2 * yfrag2 * src[((yi + i + 1)*swidth + xi + ii + 1) * 4 + 1];
                    blue += xfrag2 * yfrag2 * src[((yi + i + 1)*swidth + xi + ii + 1) * 4 + 2];
                    alpha += xfrag2 * yfrag2 * src[((yi + i + 1)*swidth + xi + ii + 1) * 4 + 3];
                }
                red /= dx * dy;
                green /= dx * dy;
                blue /= dx * dy;
                alpha /= dx * dy;
                red = clamp(red, 0, 255);
                green = clamp(green, 0, 255);
                blue = clamp(blue, 0, 255);
                alpha = clamp(alpha, 0, 255);
    
                dest[(y*dwidth+x)*4] = (unsigned char) red;
                dest[(y*dwidth+x)*4+1] = (unsigned char) green;
                dest[(y*dwidth+x)*4+2] = (unsigned char) blue;
                dest[(y*dwidth+x)*4+3] = (unsigned char) alpha;
            }
        }
    }
    

    我怀疑我的降尺度算法(sprshrink)有效(因为它是别人的!:D),并且怀疑我在testScale()中使用指针时出错了!你怎么看 ?我是否正确分配和使用指针?我做错了什么?

    图片:

    清除:

    Clear picture

    运行testScale()而不是testCopy()(注释掉testCopy)时的假象。 Artifcats after running the scaling method!

0 个答案:

没有答案