2014-12-08 2 views
0

У меня есть набор массивов (которые представляют собой «пиксели» - представление 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), второй столбец будет перемещен в два раза вправо и станет четвертой колонке. третий и четвертый столбцы будут заменены только первым и вторым столбцами.

Этого будет достаточно, если вы просто как-нибудь научитесь управлять этим, так или иначе, вы можете сосредоточиться на методе «ShiftCol» только в классе RGBImage, и вы увидите, что я сделал до сих пор в коде. Спасибо, заранее!

* ПОЖАЛУЙСТА, держите ответ простым с кодом. Я узнал только для циклов, в то время как циклы, если заявления, массивы .. Я не хочу использовать в этом проекте какой-либо другой продвинутый материал.

Вот мой код:

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 класс:

класс 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

Это только предположение, потому что есть много кода, чтобы взять здесь. Но я думаю, что ваш цикл for - это только повторение суммы смещения, но это, вероятно, должно быть (смещение * _cols) – chancea

+0

@chancea Ну, я пытаюсь как-то определить, КОТОРЫЕ столбцы не должны перемещаться, например, в ShiftCol +2 Не хочу, чтобы третий и четвертый двигались, я просто хотел, чтобы их заменили первые и второй столбцы. и если я переведу ShiftCol - 1, я хочу, чтобы только второй, третий и четвертый столбцы перемещались один влево. Я считаю, что я довольно близок к решению. Я посмотрю, что я могу сделать. также мне трудно понять, как справку * _cols помогут и где именно. –

+0

Я думаю, что путаница - это слово «столбцы» против «_cols». Я думаю, что когда вы говорите «столбец», вы имеете в виду три столбца, из которых состоит набор (3 набора столбцов составляют 1 полный столбец). Я думаю, похоже, что в вашем коде вы перемещаете каждый столбец на следующую позицию в наборе, или ваш текущий код фактически переводит его на следующую (сумму смещения)? Извините, если я не чувствую смысла. – chancea

ответ

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();     
      }  
     }   
    } 
} 
+0

Отлично! Спасибо! –

1

Во-первых, вы действительно не нужен _offset поле. Единственное, что вы используете, это метод shiftCol(), и он не является частью состояния изображения как объекта. Поэтому она должна быть локальной переменной. Но действительно, параметр offset делает работу достаточно хорошо, вам не нужна дополнительная переменная.Помните, что параметры передаются по значению, даже если вы изменяете значение offset, оно ничего не изменит в вызывающем коде.

Во-вторых, вам действительно не нужна переменная currentShift. Вы добавляете к нему один, но первый currentShift++ не находится в цикле и его дальнейшее использование не используется, а второй currentShift++ находится в цикле, но он не влияет ни на что в цикле и не используется после него , Так что - избавься от него.

Теперь, к вашей реальной проблеме. Давайте сначала посмотрим на положительное смещение. Что вы делаете для каждого столбца:

  • Поместите значение пикселя в пикселе его правой
  • Изменить текущее значение пикселя черный - дважды (первый, установив его непосредственно в _pixels[i][j], а затем снова по телефону setPixel()).

У этого есть несколько проблем. Во-первых, так как вы работаете с j от 0 к offset, что происходит это:

  • Пиксель, который был в столбце 0 находится в колонке 1, а столбец 0 почернела.
  • Пиксел, который находится в столбце 1 (который мы фактически изменили на предыдущем шаге), помещается в столбец 2, а столбец 1 почернел.
  • Затем пиксель перемещается в столбец 3 и т. Д.

Почему все эти шаги одного пикселя? И создание нового пиксельного объекта каждый раз, когда вы это делаете.

И вы просто переместили один столбец, уничтожив все значения столбцов на этом пути. Сделав это, вы потеряли всю информацию в них, которая также должна была быть перенесена!

И, конечно же, двойное назначение новых объектов, один из которых идет прямо к мусору.

Теперь, чтобы распутать этот узел.

Как правило, при копировании части массива на себя всегда важно скопировать в правильном порядке. Давайте посмотрим на простой массив символов:

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

Предположим, вы хотите переместить «BCD» часть два пробела вправо, так что результат будет «ABCBCD» (не заботясь о стирании перемещенный участие в момент). Наивно, вы думаете, что перемещение:

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

будет делать то, что нужно. но на самом деле, что вы получаете:

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

Почему существует «B» в положении 5? Потому что мы уже изменили arr[3] в нашем первом задании. Это уничтожило D, поэтому, когда мы пришли, чтобы назначить arr[3] на arr[5], это уже «B».

Правильный способ скопировать вправо, поэтому начинать с правой стороны:

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

Но ... если мы хотим, чтобы сдвинуть влево, делая это в обратном порядке, как это не будет работать. Начните снова с нашего оригинального «ABCDEF». Предположим, мы хотим сдвинуть позиции «CDE» влево, чтобы получить «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│ 
└─┴─┴─┴─┴─┴─┘ 

Поскольку arr[2] уже изменилось, когда мы добрались до него.

Вывод:

  1. Чтобы переместить часть массива вправо, вы должны начать свой цикл из высоких показателей и спуститесь к низким показателям.
  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() делает это, потому что это общедоступный метод и дает защитную копию пикселя, так что если его содержимое будет изменено, это не повлияет на наш образ. Но для внутренней операции это необязательно.

+0

Какой замечательный ответ @realSkeptic! Я уточню вам завтра, что я пробовал! Огромное спасибо!! Удивительно понять, как подходить к кодированию. Еще раз спасибо! –

Смежные вопросы