Feedback

Please leave feedback and comments. I am always interested to hear how people get on using these LScripts!

Monday 11 March 2013

LScript - Image_DigitalArtifacts

LScript (Layout) to create compressed video artifact effect.

Compatible with Newtek LightWave 9.6 and above.

// LScript Image Filter - www.StephenCulley.co.uk
//
// web   address: http://www.stephenculley.co.uk
// email address: email@stephenculley.co.uk

/* 
    LScript Image Filter - Digital Artifacts

    Image_DigitalArtifacts.ls

*/

@version 2.5
@warnings
@script image
@name *Digital Artifacts

    // Title
    sTitle = "*Digital Artifacts";

    // Version
    sVersion = "v1.0";

    iBlockSize = 8;
    iLifeRed = 2;
    iLifeGreen = 2;
    iLifeBlue = 2;
    nErrorRed = 0.03;
    nErrorGreen = 0.03;
    nErrorBlue = 0.03;
    bColorSync = false;

    aBlock = nil; // Block

    // Control
    ctrl_pr0,ctrl_c0,ctrl_c1,ctrl_c2,ctrl_c3,ctrl_c4,ctrl_c5,ctrl_c6,ctrl_c7; 

create
{
    setdesc(sTitle);
}

process: ifo
{

    // Error
    if(ifo.width < 1 || ifo.height < 1){return;}

    // Variable

    iBlock = 1;
    iBlockMultiplier = 1 / (iBlockSize * iBlockSize);
    iGridX = floor(ifo.width / iBlockSize);
    iGridY = floor(ifo.height / iBlockSize);
    _nErrorRed = nErrorRed * (iBlockSize * iBlockSize);
    _nErrorGreen = nErrorGreen * (iBlockSize * iBlockSize);
    _nErrorBlue = nErrorBlue * (iBlockSize * iBlockSize);

    // Init Block
    if(aBlock.size() <> (iGridX * iGridY) || ifo.frame == 0)
      {
      for(b = 1; b <= (iGridX * iGridY); ++b)
        {
        aBlock[b,1] = 0; // Red Count 
        aBlock[b,2] = 0; // Green Count 
        aBlock[b,3] = 0; // Blue Count 
        aBlock[b,4] = 0.0; // Red
        aBlock[b,5] = 0.0; // Green
        aBlock[b,6] = 0.0; // Blue
        } 
      }   

    iProgress = iGridX * iGridY;
    if(runningUnder() != SCREAMERNET) moninit(iProgress);

    for(gy = 0;gy <= iGridY - 1; ++gy)
      {

      for(gx = 0;gx <= iGridX - 1; ++gx)
        {
 
        _gx = gx * iBlockSize; 
        _gy = gy * iBlockSize; 

        r = 0;
        g = 0;
        b = 0;

        // Average
        for(i = 1;i <= iBlockSize; ++i)
          {
          for(j = 1;j <= iBlockSize; ++j)
            {
            r += ifo.red[j + _gx,i + _gy]; // Red
            g += ifo.green[j + _gx,i + _gy]; // Green
            b += ifo.blue[j + _gx,i + _gy]; // Blue
            }
          }

        r *= iBlockMultiplier;
        g *= iBlockMultiplier;
        b *= iBlockMultiplier;

        // Difference 
        rd = 0;
        gd = 0;
        bd = 0;

        for(i = 1;i <= iBlockSize; ++i)
          {
          for(j = 1;j <= iBlockSize; ++j)
            {
            rd += abs(ifo.red[j + _gx,i + _gy] - r);
            gd += abs(ifo.green[j + _gx,i + _gy] - g);
            bd += abs(ifo.blue[j + _gx,i + _gy] - b);
            }
          }

        // Update Block
        if(bColorSync)
          { 
          if((aBlock[iBlock,1] <= 0 && rd < _nErrorRed) || 
             (aBlock[iBlock,2] <= 0 && gd < _nErrorGreen) || 
             (aBlock[iBlock,3] <= 0 && bd < _nErrorBlue)) 
            {
            c = random(1,3);
            aBlock[iBlock,1] = c;
            aBlock[iBlock,2] = c;
            aBlock[iBlock,3] = c;
            }
          aBlock[iBlock,4] = r;
         aBlock[iBlock,5] = g;
         aBlock[iBlock,6] = b;
         }
       else
         {
         if(aBlock[iBlock,1] <= 0 && rd < _nErrorRed) // Red
           {
           aBlock[iBlock,1] = random(1,iLifeRed);
           aBlock[iBlock,4] = r;
           }

         if(aBlock[iBlock,2] <= 0 && gd < _nErrorGreen) // Green
           {
           aBlock[iBlock,2] = random(1,iLifeGreen);
           aBlock[iBlock,5] = g;
           }

         if(aBlock[iBlock,3] <= 0 && bd < _nErrorBlue) // Blue
           {
           aBlock[iBlock,3] = random(1,iLifeBlue);
           aBlock[iBlock,6] = b;
           }
         }
        
        // Read Block
        rd = aBlock[iBlock,1];
        --aBlock[iBlock,1];
        r =  aBlock[iBlock,4];
        gd = aBlock[iBlock,2];
        --aBlock[iBlock,2];
        g =  aBlock[iBlock,5];
        bd = aBlock[iBlock,3];
        --aBlock[iBlock,3];
        b =  aBlock[iBlock,6];

        // Draw Block
        for(i = 1;i <= iBlockSize; ++i)
          {
          for(j = 1;j <= iBlockSize; ++j)
            {
            if(rd > 0){ifo.red[j + _gx,i + _gy] = r;}
            if(gd > 0){ifo.green[j + _gx,i + _gy] = g;}
            if(bd > 0){ifo.blue[j + _gx,i + _gy] = b;}
            }
          }

        ++iBlock;

        if(runningUnder() != SCREAMERNET) if(monstep()) return;
        }      
      }
  
}

// CLIP

clip: min,max,n
{
    if(n < min) n = min;
    if(n > max) n = max;
    return(n);
}

load: what,io
{
    if(what == SCENEMODE)
    {
        bColorSync = io.read().asInt();
        iBlockSize = io.read().asInt();
        iLifeRed = io.read().asInt();
        iLifeGreen = io.read().asInt();
        iLifeBlue = io.read().asInt();
        nErrorRed = io.read().asNum();
        nErrorGreen = io.read().asNum();
        nErrorBlue = io.read().asNum();
    }
}

save: what,io
{
    if(what == SCENEMODE)
    {
        io.writeln(bColorSync);                
        io.writeln(iBlockSize);         
        io.writeln(iLifeRed);  
        io.writeln(iLifeGreen);
        io.writeln(iLifeBlue);        
        io.writeln(nErrorRed);         
        io.writeln(nErrorGreen);         
        io.writeln(nErrorBlue);         
    }
}

options
{
    reqbegin(sTitle + " " + sVersion);

    // Control
    ctrl_pr0 = ctlpopup("Preset",1, @"Low",
                                     "Medium",
                                     "High",
                                     "Extreme"@);

    ctlsep();
    ctrl_c0 = ctlinteger("Block Size",iBlockSize);
    ctrl_c1 = ctlcheckbox("Color Sync",bColorSync);
    ctrl_c2 = ctlinteger("Life Red",iLifeRed);
    ctrl_c3 = ctlinteger("     Green",iLifeGreen);
    ctrl_c4 = ctlinteger("     Blue",iLifeBlue);
    ctrl_c5 = ctlpercent("Error Red",nErrorRed);
    ctrl_c6 = ctlpercent("      Green",nErrorGreen);
    ctrl_c7 = ctlpercent("      Blue",nErrorBlue);

    // Developer
    ctlsep();
    ctrl_dev0 = ctltext("","developer: Stephen Culley","http://www.stephenculley.co.uk");

    // Refresh
    ctlrefresh(ctrl_pr0,"refresh_preset"); // Preset
    ctlrefresh(ctrl_c0,"refresh_c0"); // Block Size
    ctlrefresh(ctrl_c2,"refresh_c2"); // Life Red
    ctlrefresh(ctrl_c3,"refresh_c3"); // Life Green
    ctlrefresh(ctrl_c4,"refresh_c4"); // Life Blue

    ctlrefresh(ctrl_c5,"refresh_c5"); // Error Red
    ctlrefresh(ctrl_c6,"refresh_c6"); // Error Green
    ctlrefresh(ctrl_c7,"refresh_c7"); // Error Blue

    return if !reqpost();

    iBlockSize = max(1,getvalue(ctrl_c0));
    bColorSync = getvalue(ctrl_c1);
    iLifeRed = max(1,getvalue(ctrl_c2));
    iLifeGreen = max(1,getvalue(ctrl_c3));
    iLifeBlue = max(1,getvalue(ctrl_c4));
    iErroRed = max(0.0,getvalue(ctrl_c5));
    iErrorGreen = max(0.0,getvalue(ctrl_c6));
    iErrorBlue = max(0.0,getvalue(ctrl_c7));

    reqend();
}

refresh_preset:value
{
    if(value == 1) // Low
      {
      setvalue(ctrl_c0,8); // Block Size
      setvalue(ctrl_c1,0); // Sync Color
      setvalue(ctrl_c2,1); // Life Red
      setvalue(ctrl_c3,1); // Life Green
      setvalue(ctrl_c4,1); // Life Blue
      setvalue(ctrl_c5,0.02); // Error Red
      setvalue(ctrl_c6,0.02); // Error Green
      setvalue(ctrl_c7,0.02); // Error Blue
      }  

    if(value == 2) // Medium
      {
      setvalue(ctrl_c0,8); // Block Size
      setvalue(ctrl_c1,0); // Sync Color
      setvalue(ctrl_c2,2); // Life Red
      setvalue(ctrl_c3,2); // Life Green
      setvalue(ctrl_c4,2); // Life Blue
      setvalue(ctrl_c5,0.02); // Error Red
      setvalue(ctrl_c6,0.03); // Error Green
      setvalue(ctrl_c7,0.04); // Error Blue
      } 

    if(value == 3) // High
      {
      setvalue(ctrl_c0,8); // Block Size
      setvalue(ctrl_c1,0); // Sync Color
      setvalue(ctrl_c2,3); // Life Red
      setvalue(ctrl_c3,3); // Life Green
      setvalue(ctrl_c4,3); // Life Blue
      setvalue(ctrl_c5,0.02); // Error Red
      setvalue(ctrl_c6,0.04); // Error Green
      setvalue(ctrl_c7,0.06); // Error Blue
      }

    if(value == 4) // Extreme
      {
      setvalue(ctrl_c0,8); // Block Size
      setvalue(ctrl_c1,0); // Sync Color
      setvalue(ctrl_c2,9); // Life Red
      setvalue(ctrl_c3,9); // Life Green
      setvalue(ctrl_c4,9); // Life Blue
      setvalue(ctrl_c5,0.1); // Error Red
      setvalue(ctrl_c6,0.1); // Error Green
      setvalue(ctrl_c7,0.1); // Error Blue
      }
}

refresh_c0:value // Block Size
{
    iBlockSize = max(1,value);
    setvalue(ctrl_c0,iBlockSize);
}

refresh_c2:value // Life Red
{
    iLifeRed = max(1,value);
    setvalue(ctrl_c2,iLifeRed);
}

refresh_c3:value // Life Green
{
    iLifeGreen = max(1,value);
    setvalue(ctrl_c3,iLifeGreen);
}

refresh_c4:value // Life Blue
{
    iLifeBlue = max(1,value);
    setvalue(ctrl_c4,iLifeBlue);
}

refresh_c5:value // Error Red
{
    nErrorRed = clip(0.0,1.0,value);
    setvalue(ctrl_c5,nErrorRed);
}

refresh_c6:value // Error Green
{
    nErrorGreen = clip(0.0,1.0,value);
    setvalue(ctrl_c6,nErrorGreen);
}

refresh_c7:value // Error Blue
{
    nErrorBlue = clip(0.0,1.0,value);
    setvalue(ctrl_c7,nErrorBlue);
}


All scripts available at my Google Drive at
https://drive.google.com/open?id=1cR_q2GVUAJHumic1-A3eXV16acQnVTWs

4 comments:

  1. Cool lscript, thank you.

    Would it possible to add envelopes, to be able to animate the blockiness over time?

    ReplyDelete
    Replies
    1. Do you mean opacity of the effect, or just the controls? The only control that would be difficult to change would be block size due it it needing to change array sizes and data would be lost. Otherwise, I could make it have envelopes. Maybe add opacity as well tho that will slow down processing?

      Stephen

      Delete
    2. It would be the size of the blocks (Block Size) that would be cool to be able to animate over time.
      I guess it would be like a zoom effect into an image so the blocky pixels look like they are getting bigger.

      Delete
    3. This is an old script so what I'll do is create a quick script to generate block effects since to be able to change block size would require a slight rewrite to implement. I'll sort an example of it over tomorrow.

      Stephen

      Delete