我有一组数组(例如“像素” - 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);
}
}
答案 0 :(得分:1)
首先,您并不需要_offset
字段。您使用它的唯一地方是shiftCol()
方法,它实际上不是作为对象的图像状态的一部分。因此它应该是一个局部变量。但实际上,参数offset
正在很好地完成工作,您不需要额外的变量。请记住,参数按值传递,即使您更改了offset
的值,它也不会更改调用代码中的任何内容。
其次,你真的不需要变量currentShift
。您正在添加一个,但第一个currentShift++
不在循环中,并且没有进一步使用它,第二个currentShift++
处于循环中,但它不会影响循环中的任何内容都不会在它之后使用。所以 - 摆脱它。
现在,对你真正的问题。让我们先看一下正偏移量。你为每一栏做的是:
_pixels[i][j]
中直接设置,然后再调用setPixel()
)。这有几个问题。首先,由于您使用j
从0
运行到offset
,所以会发生以下情况:
为什么一个像素的所有这些移动?每次执行时都会创建一个新的像素对象。
你刚刚移动了一个列,在此过程中销毁了所有列值。这样做,你丢失了应该被移动的所有信息!
然后,当然,新对象的双重赋值,其中一个直接进入垃圾。
现在解开这个结。
通常,当您将数组的一部分复制到自身时,以正确的顺序复制始终很重要。让我们看一个简单的字符数组:
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]
。
<强>结论:强>
另请注意,将块移动一个地方然后再移动一个地方等没有意义 - 它只会浪费时间(如果您创建新对象,则会占用内存)。你应该把它直接转移到它应该的位置。如果你应该将它移动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();
}
}
}
}