java - 左右移动像素图像

标签 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 语句、数组......我不想在这个项目中使用任何其他高级 Material 。

这是我的代码:

RGB颜色类:

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;
    }

}

RGB图像类:

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 类:

公开课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);
}

}

最佳答案

首先,您实际上并不需要 _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│
└─┴─┴─┴─┴─┴─┘

Suppose you want to move the "BCD" part two spaces to the right, so that the result would be "ABCBCD" (not caring about erasing the moved part at the moment). Naively, you think that moving:

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

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

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

Why is there a "B" in position 5? Because we have already changed arr[3] in our first assignment. Doing that destroyed the D, so when we come to assign arr[3] to arr[5], it's already "B".

The correct way to copy to the right is therefore to start from the right:

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

但是...如果我们想向左移动,那么以相反的顺序进行操作是行不通的。从我们原来的“ABCDEF”重新开始。假设我们想将“CDE”向左移动2个位置以获得“CDEDEF”。如果我们反过来做:

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

然后,我们再次得到:

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

Because arr[2] was already changed when we got to it.

Conclusion:

  1. To shift part of an array to the right, you have to start your loop from the high indexes and go down to the low indexes.
  2. To shift part of an array to the left, you have to start your loop from the low indexes and go up to the high indexes.

Also note that there is no point in moving the block one place and then one more place etc. - it just wastes time (and memory if you create new objects). You should shift it directly to where it is supposed to be. If you are supposed to move it by 2, then its new index is j+2.

Now, let's suppose our array is like the rows in your problem. We want to shift all the contents, not just part, and fill in with blanks.

So if I want to shift this array 2 positions to the right:

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

I expect to get:

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

I now know I have to start on the right to do it correctly. What I do is look at each position from 5 down to 0, and think: what is the source for this position? It's supposed to be the cell such that I'm currently two positions to the right of. That is, the cell that's two position to my left. Is there such a cell? If so, put its value in the current index. If not (because the source position is negative), then I fill in with a blank:

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

如果您明白了,您现在就可以将我对字符数组所做的操作应用到您的像素行。

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

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

关于java - 左右移动像素图像,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27362204/

相关文章:

带有容器对象键的Java Map,通过容器对象字段值查找?

java - 更新语句只运行一次。?

java - 从 Java 访问 SDF SQLServer Mobile 文件

java - 确定二维整数数组中的连续数字

java - 带有 Maven 客户表单 Web 应用程序的 Spring MVC 无法正常工作

java - 从 Mysql 中检索并在 JSP 中显示数据

用于查找 3D 空间中线和点之间距离的 Java 代码

java - 为什么创建具有初始容量的 ArrayList 很慢?

java - 按期限长度排序的 Hibernate 标准

java - jdbc url 定义