簡體   English   中英

左右移動像素圖像

[英]Shifting a pixel image left and right

我有一組數組(例如“像素”-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類:

公共課程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() )。

這有幾個問題。 首先,由於使用j0offset進行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│
└─┴─┴─┴─┴─┴─┘

為什么在位置5出現“ B”? 因為我們已經在第一次分配中更改了arr[3] 這樣做破壞了D ,因此當我們將arr[3]分配給arr[5] ,它已經是“ B”。

因此,正確復制到右側的方法是從右側開始:

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│
└─┴─┴─┴─┴─┴─┘

因為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()這樣做是因為它是一個公共方法,並提供了像素的保護副本,因此,如果更改其內容,則不會影響我們的圖像。 但是對於內部操作而言,則沒有必要。

試試這個方法:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM