Author Topic: Defect Map Questions  (Read 9758 times)

Offline Juan Conejero

  • PTeam Member
  • PixInsight Jedi Grand Master
  • ********
  • Posts: 7111
    • http://pixinsight.com/
Re: Defect Map Questions
« Reply #15 on: 2010 November 03 06:35:13 »
Hi,

Oriol Lehmkuhl and Ivette Rodríguez wrote a nice script for cosmetic correction of bad rows and columns, back in 2008. The original thread is here. I'll copy the source code of the last version of this script here, for your convenience (warning: this code is from the last post of the original thread):

Code: [Select]
// Script to correct columns and row defects of an image
// Based on the script from the image processing tutorial:
// "NGC 5189 from GeminiObservatory..." by J.Conejero
// and on the script to average two columns by Sander:
// http://pixinsight.com/forum/viewtopic.php?t=748


#include <pjsr/Sizer.jsh>
#include <pjsr/FrameStyle.jsh>
#include <pjsr/TextAlign.jsh>
#include <pjsr/StdButton.jsh>
#include <pjsr/StdIcon.jsh>
#include <pjsr/UndoFlag.jsh>
#include <pjsr/ColorSpace.jsh>
#include <pjsr/UndoFlag.jsh>
#include <pjsr/DataType.jsh>

console.hide();

var window = ImageWindow.activeWindow;

function FLUserData() {
    this.fixColumn = true;
    this.fixRow    = false;
    this.position  = 0;

    this.doColumns = false;
    this.doRows    = false;
    this.columns   = new Array;
    this.rows      = new Array;
    this.average   = true;
}
var userData = new FLUserData;

if ( window.isNull )
    throw Error( "There is no active image window!" );

var view = window.mainView;

function FixLinesDialog() {
    this.__base__ = Dialog;
    this.__base__();

    //

    var emWidth = this.font.width( 'M' );
    var labelWidth1 = this.font.width( "Maximum planet radius (px):" );
    var spinWidth1 = 8*emWidth;

    //

    this.helpLabel = new Label( this );
    this.helpLabel.frameStyle = FrameStyle_Box;
    this.helpLabel.margin = 4;
    this.helpLabel.wordWrapping = true;
    this.helpLabel.useRichText = true;
    this.helpLabel.text = "<b>FixLines Script</b> - Script to correct  "+
        "columns or rows defects in an image."
    //

    this.colRowTreeBox = new TreeBox( this );
    this.colRowTreeBox.multipleSelection = true;
    this.colRowTreeBox.rootDecoration = false;
    this.colRowTreeBox.setMinSize( 500, 200 );
    this.colRowTreeBox.numberOfColumns = 2;
    this.colRowTreeBox.headerVisible = false;
    //       

    this.size_Label = new Label( this );
    this.size_Label.text = "Column/Row position (px):";
    this.size_Label.textAlignment = TextAlign_Right|TextAlign_VertCenter;
    this.size_Label.minWidth = labelWidth1;

    this.size_SpinBox = new SpinBox( this );
    this.size_SpinBox.minValue = 0;
    this.size_SpinBox.maxValue = Math.max(view.image.height,view.image.width);
    this.size_SpinBox.value = 0 ;
    this.size_SpinBox.setFixedWidth( spinWidth1 );
    this.size_SpinBox.toolTip = "Column or Row position";

    this.size_SpinBox.onValueUpdated = function( value )
    {
        userData.position = value;
    };

    this.size_Sizer = new HorizontalSizer;
    this.size_Sizer.spacing = 4;
    this.size_Sizer.add( this.size_Label );
    this.size_Sizer.add( this.size_SpinBox );
    this.size_Sizer.addStretch();

    // Type of defect: label
    this.typeOfDefectLab = new Label (this);
    with (this.typeOfDefectLab) {
        text = "Type of Defect:";
        textAlignment = TextAlign_Right | TextAlign_VertCenter;
        minWidth = labelWidth1;
    }
    // Type of defect: radio buttons
    this.typeOfDefectCol = new RadioButton (this);
    with (this.typeOfDefectCol) {
        text = "Column";
        checked=true;
        onCheck = function(checked) {
            userData.fixColumn = checked;
        }
    }

    this.typeOfDefectRow = new RadioButton (this);
    with (this.typeOfDefectRow) {
        text = "Row";
        onCheck = function(checked) {
            userData.fixRow = checked;
        }
    }

    // mask blur method: sizer
    this.typeOfDefectSize = new HorizontalSizer (this);
    with (this.typeOfDefectSize) {
        spacing = 16;
        add (this.typeOfDefectLab);
        add (this.typeOfDefectCol);
        add (this.typeOfDefectRow);
        addStretch();
    }

    //

    this.addButton = new PushButton( this );
    this.addButton.text = " Add ";
    this.addButton.onClick = function() {
       this.dialog.colRowTreeBox.canUpdate = false;
       if(userData.fixColumn) {
           var isDone = false;
           for(var i=0;i<userData.columns.length;++i)
                if(userData.position==userData.columns[i]) isDone = true;
           if(!isDone) {
               var node = new TreeBoxNode(this.dialog.colRowTreeBox);
               node.setText(0,"column");
               node.setText(1,format("%d",userData.position));
               userData.columns.push(userData.position);
               userData.doColumns = true;
           }
       } else {
           var isDone = false;
           for(var i=0;i<userData.rows.length;++i)
               if(userData.position==userData.rows[i]) isDone = true;
           if(!isDone) {
               var node = new TreeBoxNode(this.dialog.colRowTreeBox);
               node.setText(0,"row");   
               node.setText(1,format("%d",userData.position));
               userData.rows.push(userData.position);
               userData.doRows = true;
           }
       }
       this.dialog.colRowTreeBox.canUpdate = true;
    };

    this.removeButton = new PushButton( this );
    this.removeButton.text = " Remove ";
    this.removeButton.onClick = function() {
        for ( var i = this.dialog.colRowTreeBox.numberOfChildren; --i >= 0; )
            if ( this.dialog.colRowTreeBox.child( i ).selected) {
                if(this.dialog.colRowTreeBox.child(i).text(0)=="column") {
                        userData.columns.length = 0;
                        userData.doColumns = false;
                        for (var ii = 0; ii < this.dialog.colRowTreeBox.numberOfChildren; ++ii )
                            if ( !this.dialog.colRowTreeBox.child( ii ).selected ) {
                                userData.columns.push(this.dialog.colRowTreeBox.child(ii).text(1));
                                userData.doColumns=true;
                            }
                } else {
                        userData.rows.length = 0;
                        userData.doRows = false;
                        for (var ii = 0; ii < this.dialog.colRowTreeBox.numberOfChildren; ++ii )
                            if ( !this.dialog.colRowTreeBox.child( ii ).selected ) {
                                userData.rows.push(this.dialog.colRowTreeBox.child(ii).text(1));
                                userData.doRows = true;
                            }
                }
                this.dialog.colRowTreeBox.remove(i);
                break;
            }

    };

    this.addRemButtonsSizer = new HorizontalSizer;
    this.addRemButtonsSizer.spacing = 4;
    this.addRemButtonsSizer.add( this.typeOfDefectSize );
    this.addRemButtonsSizer.addStretch();
    this.addRemButtonsSizer.add( this.addButton );
    this.addRemButtonsSizer.add( this.removeButton );

    //
   
    this.colRowGroupBox = new GroupBox( this );
    this.colRowGroupBox.title = "Defects to correct:";
    this.colRowGroupBox.sizer = new VerticalSizer;
    this.colRowGroupBox.sizer.margin = 4;
    this.colRowGroupBox.sizer.spacing = 4;
    this.colRowGroupBox.sizer.add( this.colRowTreeBox, 100 );
    this.colRowGroupBox.sizer.add( this.size_Sizer );
    this.colRowGroupBox.sizer.add( this.addRemButtonsSizer );

    //

    this.save_Button = new PushButton( this );
    this.save_Button.text = " Save ";

    this.save_Button.onClick = function()
    {
        var saveFile = new SaveFileDialog;
        if(saveFile.execute()) {
            var fileName = saveFile.fileName;
            var f = new File;
            f.createForWriting(fileName);
            f.write(userData.columns.length,DataType_UInt16);
            console.writeln(" number of columns "+userData.columns.length);
            if(userData.columns.length!=0) f.write(userData.columns,DataType_Int32);
            f.write(userData.rows.length,DataType_UInt16);
            console.writeln(" number of rows "+userData.rows.length);
            if(userData.rows.length!=0) f.write(userData.rows,DataType_Int32);
            f.close();
        }
    };
    //

    this.load_Button = new PushButton( this );
    this.load_Button.text = " Load ";



    this.load_Button.onClick = function()
    {
        var loadFile = new OpenFileDialog;
        if(loadFile.execute()) {
            var fileName = loadFile.fileName;
            var f = new File;

            f.openForReading(fileName);

            for (var i = this.dialog.colRowTreeBox.numberOfChildren; i >= 0; --i) this.dialog.colRowTreeBox.remove(i);

            userData.columns.length = 0;
            userData.doColumns = false;
           
            var size = f.read(DataType_UInt16,1);
            if(size!=0) {
                userData.doColumns = true;
                if(size!=1) userData.columns = f.read(DataType_Int32,size);
                else        userData.columns.push(f.read(DataType_Int32,size));
                this.dialog.colRowTreeBox.canUpdate = false;
                for (var i = 0;i<size; i++) {
                    var node = new TreeBoxNode(this.dialog.colRowTreeBox);
                    node.setText(0,"column");
                    node.setText(1,format("%d",userData.columns[i]));
                }
                this.dialog.colRowTreeBox.canUpdate = true;
            }

            userData.rows.length = 0;
            userData.doRows = false;
           
            size = f.read(DataType_UInt16,1);
            if(size!=0) {
                userData.doRows = true;
                if(size!=1) userData.rows = f.read(DataType_Int32,size);
                else        userData.rows.push(f.read(DataType_Int32,size));
                this.dialog.colRowTreeBox.canUpdate = false;
                for (var i = 0;i<size; i++) {
                    var node = new TreeBoxNode(this.dialog.colRowTreeBox);
                    node.setText(0,"row");
                    node.setText(1,format("%d",userData.rows[i]));
                }
                this.dialog.colRowTreeBox.canUpdate = true;
            }
            f.close();
        }
    };
    //

    this.ok_Button = new PushButton( this );
    this.ok_Button.text = " OK ";

    this.ok_Button.onClick = function()
    {
        this.dialog.ok();
    };

    this.cancel_Button = new PushButton( this );
    this.cancel_Button.text = " Cancel ";

    this.cancel_Button.onClick = function()
    {
        this.dialog.cancel();
    };

    this.buttons_Sizer = new HorizontalSizer;
    this.buttons_Sizer.spacing = 4;
    this.buttons_Sizer.add( this.load_Button );
    this.buttons_Sizer.add( this.save_Button );
    this.buttons_Sizer.addStretch();
    this.buttons_Sizer.add( this.ok_Button );
    this.buttons_Sizer.add( this.cancel_Button );

    //

    this.sizer = new VerticalSizer;
    this.sizer.margin = 6;
    this.sizer.spacing = 6;
    this.sizer.add( this.helpLabel );
    this.sizer.addSpacing( 4 );
    this.sizer.add( this.colRowGroupBox );
    this.sizer.add( this.buttons_Sizer );

    this.windowTitle = "FixLines Script";
    this.adjustToContents();
    this.setFixedSize();
}

FixLinesDialog.prototype = new Dialog;

function FixColumn( image, col, channel)
{
    image.selectedChannel = channel;
    for ( var y = 0; y < image.height; ++y )
        image.setSample( (image.sample( col-1, y, channel ) + image.sample( col+1, y , channel ))/2, col, y , channel );
}

function FixRow( image, row, channel)
{
    image.selectedChannel = channel;
    for ( var x = 0; x < image.width; ++x )
        image.setSample( (image.sample( x, row-1, channel ) + image.sample( x , row+1, channel ))/2, x, row, channel );
}

function fixLinesEngine(userData) {
   var view = window.mainView;

   with (view) {
       beginProcess();

       var isGray = image.colorSpace==ColorSpace_Gray;

       if(userData.doColumns) {
           if(isGray) {
               for(var i=0;i<userData.columns.length;++i) {
                   FixColumn(image, userData.columns[i], 0);
               }
           } else {
               for(var i=0;i<userData.columns.length;++i) {
                   FixColumn(image,userData.columns[i], 0);
                   FixColumn(image,userData.columns[i], 1);
                   FixColumn(image,userData.columns[i], 2);
               }
           }
       }
       if(userData.doRows) {
           if(isGray) {
               for(var i=0;i<userData.rows.length;++i) {
                   FixRow(image, userData.rows[i], 0);
               }
           } else {
               for(var i=0;i<userData.rows.length;++i) {
                   FixRow(image,userData.rows[i], 0);
                   FixRow(image,userData.rows[i], 1);
                   FixRow(image,userData.rows[i], 2);
               }
           }
       }
       endProcess();
   }
}

function main() {
    var dialog = new FixLinesDialog();
    dialog.view = view;
    if ( dialog.execute() )
      fixLinesEngine(userData);
}

main();

This is a very nice utility that for some odd reason was not included in the standard set of scripts with all PixInsight distributions. My fault, which I'll try to fix in the next version.

Below is a nice example of the type of results that can be achieved with this little but powerful script:





Hope this helps!
Juan Conejero
PixInsight Development Team
http://pixinsight.com/

Offline Juan Conejero

  • PTeam Member
  • PixInsight Jedi Grand Master
  • ********
  • Posts: 7111
    • http://pixinsight.com/
Re: Defect Map Questions
« Reply #16 on: 2010 November 03 07:07:00 »
Hi William,

Quote
I can't wait for version 1.6 with it's (hopefully complete) help system. I hope that when it does appear it is complete and makes no assumptions of prior knowledge (at least with regard to the interface). In fact, I may just wait until it appears before I even try to proceed any further up the learning curve for the interface. That could save me a fair amount of frustration, it seems to me.

I understand your frustration. I'm going to rewrite the FAQ answer that you've quoted as soon as I finish this post, since it no longer reflects the actual state of things regarding documentation and a user manual.

Trust me that I'm doing all I can do to generate and improve the necessary documentation. Unfortunately, the next release still won't include a complete documentation system. That is simply impossible because writing a documentation for all existing tools requires months of hard work. I hope that at least the most important and complex tools will be documented. The next version will include the new documentation system fully functional, as I've described in the release information board, but the documentation contents will still be incomplete.

On the other hand, the graphical user interface also needs documentation. This is another pending task, but I think the interface is now quite well documented with many and excellent video tutorials. New video tutorials will be created, but again this also requires a lot of time.

Keep in mind that I cannot stop development. Quite at the contrary, many development tasks require urgent attention. For example, right now there are several important bugs that must be fixed on all platforms, and some new important tools that should be included in all distributions. The development frameworks also require urgent attention, with lots of requested features and problems that are currently stopping PI developers, and hence must be addressed now. So I have to divide my working time and efforts into many different tasks, including development of the core application, development of new and improved tools, fixing bugs everywhere, writing documentation, making video tutorials, user support, ... just to name the main fronts.

So once more, I ask for patience. In the meanwhile, please feel free to ask here whatever doubt you may have and we'll do our best to help you.
Juan Conejero
PixInsight Development Team
http://pixinsight.com/