左右移动像素图像

时间:2014-12-08 16:17:15

标签: java

我有一组数组(例如“像素” - RGB表示),例如

(0,0,0)(0,0,0)(0,0,0)(0,0,0)
(1,1,1)(1,1,1)(1,1,1)(1,1,1)
(2,2,2)(2,2,2)(2,2,2)(2,2,2)

我想左右移动列和向上/向下移动行。例如:

ShiftCol + 2将产生输出:

(0,0,0)(0,0,0)(0,0,0)(0,0,0)
(0,0,0)(0,0,0)(1,1,1)(1,1,1)
(0,0,0)(0,0,0)(2,2,2)(2,2,2)

ShiftRow - 1将产生输出:(在ShiftCol +2之后)

(0,0,0)(0,0,0)(0,0,0)(0,0,0)
(0,0,0)(0,0,0)(0,0,0)(0,0,0)
(0,0,0)(0,0,0)(1,1,1)(1,1,1)

(上面输出中发生的事情是:第一行移动到第二行,第二行移动到第三行,第一行变为黑色(仅为零),第三行仅替换为第二行。

ShiftCol- 1将产生输出:

(0,0,0)(0,0,0)(0,0,0)(0,0,0)
(0,0,0)(0,0,0)(0,0,0)(0,0,0)
(0,0,0)(1,1,1)(1,1,1)(0,0,0)

我只需要你的帮助就可以告诉我如何将每一列“移动”到右边,这就足够了。我设法做的是调用ShiftCol +2时,第一列向右移动2列(并出现在第三列),前两列转为(0,0,0)黑色颜色。问题是我不知道如何根据调用向右移动的数字向右移动每一列,例如 - 如果我调用ShiftCol(2)并且像素图像数组是3x4,你可以在输出应该发生的是:第一列将向右移动两次 - 到第三列,第一列将变为黑色(0,0,0),第二列也将向右移动两次并将变为第四栏。第三列和第四列将被第一列和第二列替换。

如果你只是以某种方式指导我如何管理它就足够了,无论如何你只能在RGBImage类中关注方法“ShiftCol”,你会看到我在代码中到目前为止所取得的成就。先谢谢你!

*请,请使用代码简化答案。我学会了for循环,while循环,if语句,数组..我不想在这个项目中使用任何其他高级材料。

这是我的代码:

RGBColor类:

public class RGBColor {
        /**
         * attributes: red, green and blue component of a color.
         */
        private int _red,_green,_blue;

        /**
         * final variables.
         */
        private final int MAX_VALUE = 255,MIN_VALUE = 0;
        private final double THIRTY_PERCENT = 0.3,FIFTY_NINE_PERCENT = 0.59,ELEVEN_PERCENT = 0.11;                   

        /**
         * Consctructor which gets 3 colors (RGB), we check here if their range is valid (0 - 255), if not we assign black to it.
         *
         *  @param red - The red color component value.
         *  @param green - The green color component value.
         *  @param blue - The blue color component value
         */
        public RGBColor(int red, int green, int blue)
        {
            if(isValid(red,green,blue))
            {
                _red   = red;
                _green = green;
                _blue  = blue;
            }
            else
                doBlack();
        }


        /**
         * Construct a black RGBColor. i.e. red = green = blue = 0
         */
        public RGBColor()
        {
        doBlack();
    }



    /**
     * Here we check if the color number was entered correctly.
     * It has to be an integer (whole number) between 0-255.
     * 
     * @param nums - a component value, should be the number between 1-4
     * @param return - return true if the number is between 1-4, false otherwise.
     */
    private boolean isValid(int nums)
    {
        return ((nums >= MIN_VALUE) && (nums <= MAX_VALUE));
    }

    /**
     * Here we check if the color number was entered correctly.
     * It has to be an integer (whole number) between 0-255.
     * 
     * @param red - the red component
     * @param green - the green component
     * @param blue - the red component
     * @param return true if values are correct, false otherwise.
     */
    private boolean isValid(int red, int green, int blue)
    {
        return ((red <= MAX_VALUE && red >= MIN_VALUE && 
                green <= MAX_VALUE && green >= MIN_VALUE &&
                blue <= MAX_VALUE && blue >= MIN_VALUE));
    }
    /**
     * Returns RGB color string triplet with numbers between 0-255, i.e. (0,127,127)
     */
    public String toString()
    {
        return ("(" + _red + "," + _green + "," + _blue + ")");
    }

    /**
     * RGBColor will become the color Black. (0,0,0)
     */
    private void doBlack()
    {
        _red = _green = _blue = 0;
    }

}

RGBImage类:

public class RGBImage
{
  private int _rows, _cols;
 private RGBColor[][] _pixels;
 private int _offset = 0;

  public RGBImage(int rows, int cols)
{
  _rows = rows;
  _cols = cols;
  _pixels = new RGBColor[_rows][_cols];
  for(int i = 0; i < _rows; i++)
    for(int j = 0; j < _cols; j++)
        _pixels[i][j] = new RGBColor();
}

public RGBImage(RGBColor[][] pixels)
{
    _rows = pixels.length;
    _cols = pixels[0].length;
    _pixels = new RGBColor[_rows][_cols];
    for(int i = 0; i < _rows; i++)
        for(int j = 0; j < _cols; j++)
         _pixels[i][j] = new RGBColor(pixels[i][j]);    
}



 public void shiftCol (int offset)
{
    if(_offset == 0)
        _offset = offset;
    else
        _offset += offset;

    int currentShift = 1;

    if( (_offset == _cols) || (-_offset == _cols) ){
        makeBlack(_rows,_cols); //make black
    }    
    else if( (_offset < _cols) || (-_offset < _cols) )
    {
        if(_offset > 0){
            for(int j = currentShift; j < _cols && j <= _offset; j++){
                for(int i = 0; i < _rows; i++){
                    setPixel(i,j + 1,this._pixels[i][j]);
                    setPixel(i,j,this._pixels[i][j] = new RGBColor());
                }    
            }
            _offset++;
            currentShift++;
        }
        else if(offset < 0){
            offset = -offset;
            for(int j = currentShift; j < _cols && j <= offset; j++){
                for(int i = 0; i < _rows; i++){
                    setPixel(i,_cols - 1 - j,this._pixels[i][_cols - j]);
                    setPixel(i,_cols,this._pixels[i][_cols - j] = new RGBColor());
                }
                currentShift++;
            }   
        } 
    } 
}
public void setPixel(int row, int col, RGBColor pixel)
{
    if ((pixel != null) && (row < _pixels.length) && (col < _pixels[0].length))
        _pixels[row][col] = new RGBColor(pixel);
}

public String toString()
{
    String pixelSet ="";
    for (int i = 0; i < _rows; i++){
        for(int j = 0; j < _cols; j++){
            pixelSet += this._pixels[i][j].toString();
        }
        pixelSet += "\n";
    }
    //pixelSet += tester;
    return pixelSet;
} 

}

和我的输出测试器类:

StudentTester课程:

public class StudentTester {

public static void main(String[] args) {

    System.out.println("Black Image Constructor:");
    RGBImage rgbImg0 = new RGBImage(3,4);       
    System.out.println(rgbImg0);    

    System.out.println("Constructor with RGBColor[][] Array Parameter:");
    RGBColor[][] rgbArray1 = new RGBColor[5][4];
    for (int i=0; i<rgbArray1.length;i++)
        for (int j=0; j<rgbArray1[0].length;j++)    
            rgbArray1[i][j] = new RGBColor(i,i,i);                      
    RGBImage rgbImg1 = new RGBImage(rgbArray1);
    System.out.println(rgbImg1);

    System.out.println("Copy Constructor:");
    RGBImage rgbImg2 = new RGBImage(rgbImg1);
    System.out.println(rgbImg2);

    System.out.println("flipVertical:");
    rgbImg1.flipVertical();
    System.out.println(rgbImg1);

    System.out.println("rotateClockwise:");
    rgbImg1.rotateClockwise();
    System.out.println(rgbImg1);

    System.out.println("shiftCol 2:");
    rgbImg1.shiftCol(3);
    System.out.println(rgbImg1);

    System.out.println("shiftCol 2:");
    rgbImg1.shiftCol(-2);
    System.out.println(rgbImg1);

    System.out.println("shiftCol 2:");
    rgbImg1.shiftCol(1);
    System.out.println(rgbImg1);
}

}

2 个答案:

答案 0 :(得分:1)

首先,您并不需要_offset字段。您使用它的唯一地方是shiftCol()方法,它实际上不是作为对象的图像状态的一部分。因此它应该是一个局部变量。但实际上,参数offset正在很好地完成工作,您不需要额外的变量。请记住,参数按值传递,即使您更改了offset的值,它也不会更改调用代码中的任何内容。

其次,你真的不需要变量currentShift。您正在添加一个,但第一个currentShift++不在循环中,并且没有进一步使用它,第二个currentShift++处于循环中,但它不会影响循环中的任何内容都不会在它之后使用。所以 - 摆脱它。

现在,对你真正的问题。让我们先看一下正偏移量。你为每一栏做的是:

  • 将像素的值放在右侧的像素中
  • 将像素的当前值更改为黑色 - 两次(首先在_pixels[i][j]中直接设置,然后再调用setPixel())。

这有几个问题。首先,由于您使用j0运行到offset,所以会发生以下情况:

  • 第0列中的像素位于第1列,第0列显示为黑色。
  • 第1列中的像素(我们在上一步中实际更改过)放在第2列,第1列变黑。
  • 然后像素移动到第3列,依此类推。

为什么一个像素的所有这些移动?每次执行时都会创建一个新的像素对象。

你刚刚移动了一个列,在此过程中销毁了所有列值。这样做,你丢失了应该被移动的所有信息!

然后,当然,新对象的双重赋值,其中一个直接进入垃圾。

现在解开这个结。

通常,当您将数组的一部分复制到自身时,以正确的顺序复制始终很重要。让我们看一个简单的字符数组:

 0 1 2 3 4 5
┌─┬─┬─┬─┬─┬─┐
│A│B│C│D│E│F│
└─┴─┴─┴─┴─┴─┘

假设您要移动&#34; BCD&#34;第二部分是右边的空格,因此结果将是&#34; ABCBCD&#34; (此刻并不关心擦除被移动的部分)。天真地,你认为移动:

arr[3] = arr[1];
arr[4] = arr[2];
arr[5] = arr[3];

将会做正确的事情。但事实上,你得到的是:

 0 1 2 3 4 5
┌─┬─┬─┬─┬─┬─┐
│A│B│C│B│C│B│
└─┴─┴─┴─┴─┴─┘

为什么会出现&#34; B&#34;在第5位?因为我们在第一次分配时已经更改了arr[3]。这样做会破坏D,所以当我们将arr[3]分配给arr[5]时,它已经&#34; B&#34;。

因此,向右复制的正确方法是从右侧开始:

arr[5] = arr[3];
arr[4] = arr[2];
arr[3] = arr[1];

但是......如果我们想要向左移动,那么按照相反的顺序进行,就行不通。从我们原来的&#34; ABCDEF&#34;开始。假设我们要转移&#34; CDE&#34;左边2个位置得到&#34; CDEDEF&#34;。如果我们反过来这样做:

arr[2] = arr[4];
arr[1] = arr[3];
arr[0] = arr[2];

然后,我们得到:

 0 1 2 3 4 5
┌─┬─┬─┬─┬─┬─┐
│E│D│E│D│E│F│
└─┴─┴─┴─┴─┴─┘

因为我们到达时已经更改了arr[2]

<强>结论:

  1. 要将数组的一部分向右移动,您必须从高索引开始循环并转到低索引。
  2. 要将数组的一部分移到左侧,您必须从低索引开始循环并转到高索引。
  3. 另请注意,将块移动一个地方然后再移动一个地方等没有意义 - 它只会浪费时间(如果您创建新对象,则会占用内存)。你应该把它直接转移到它应该的位置。如果你应该将它移动2,那么它的新索引是j+2

    现在,让我们假设我们的数组就像问题中的行一样。我们希望转移所有内容,而不仅仅是部分内容,并填空。

    因此,如果我想将此阵列的2个位置向右移动:

     0 1 2 3 4 5
    ┌─┬─┬─┬─┬─┬─┐
    │A│B│C│D│E│F│
    └─┴─┴─┴─┴─┴─┘
    

    我希望得到:

     0 1 2 3 4 5
    ┌─┬─┬─┬─┬─┬─┐
    │ │ │A│B│C│D│
    └─┴─┴─┴─┴─┴─┘
    

    我现在知道我必须从右边开始正确地做到这一点。我所做的是从5到0看每个位置,并思考:这个位置的来源是什么?它应该是单元格,因此我目前位于右侧的两个位置。也就是说,两个位于我左边的单元格。有这样的细胞吗?如果是这样,请将其值放在当前索引中。如果不是(因为源位置是负数),那么我填空:

    for ( i = arr.length - 1; i >= 0; i-- ) {
        if ( i - offset >= 0 ) {
            arr[i] = arr[i-offset];
        } else {
            arr[i] = ' ';
        }
    }
    

    如果您有了这个想法,那么您现在可以将我对字符数组所做的操作应用到您的像素行。

    您的下一个任务应该是将反向逻辑应用于负偏移(记住,从左到右!)

    最后一点:不要使用setPixel()进行此复制操作。它会创建新的像素对象,而这实际上是不必要的(黑色部分除外)。我认为setPixel()这样做是因为它是一种公共方法,并提供了像素的保护副本,这样如果其内容发生变化,它就不会影响我们的图像。但对于内部操作,这是不必要的。

答案 1 :(得分:1)

试试这个方法:

public void shiftCol (int offset)
{
    if(offset > 0){
       for(int j = _cols - 1; j >= 0; j--){
          for(int i = 0; i < _rows; i++){
              if (j - offset >= 0) 
                  _pixels[i][j] = _pixels[i][j-offset];
              else
                  _pixels[i][j] = new RGBColor();                    
          }    
       }
    } else {
       for(int j = 0; j <=_cols - 1; j++){
          for(int i = 0; i < _rows; i++){
              if (j - offset < _cols) 
                 _pixels[i][j] = _pixels[i][j-offset];
              else
                 _pixels[i][j] = new RGBColor();                   
          }    
       }         
    }
}