1

I am playing around with images and the random number generator in Python, and I would like to understand the strange output picture my script is generating.

The larger script iterates through each pixel (left to right, then next row down) and changes the color. I used the following function to offset the given input red, green, and blue values by a randomly determined integer between 0 and 150 (so this formula is invoked 3 times for R, G, and B in each iteration):

def colCh(cVal):
  random.seed()
  rnd = random.randint(0,150)
  newVal = max(min(cVal - 75 + rnd,255),0)
  return newVal

My understanding is that random.seed() without arguments uses the system clock as the seed value. Given that it is invoked prior to the calculation of each offset value, I would have expected a fairly random output.

When reviewing the numerical output, it does appear to be quite random:

Scatter plot of every 100th R value as x and R' as y: img

However, the picture this script generates has a very peculiar grid effect:

Output picture with grid effect hopefully noticeable: img

Furthermore, fwiw, this grid effect seems to appear or disappear at different zoom levels.

I will be experimenting with new methods of creating seed values, but I can't just let this go without trying to get an answer.

Can anybody explain why this is happening? THANKS!!!

Update: Per Dan's comment about possible issues from JPEG compression, the input file format is .jpg and the output file format is .png. I would assume only the output file format would potentially create the issue he describes, but I admittedly do not understand how JPEG compression works at all. In order to try and isolate JPEG compression as the culprit, I changed the script so that the colCh function that creates the randomness is excluded. Instead, it merely reads the original R,G,B values and writes those exact values as the new R,G,B values. As one would expect, this outputs the exact same picture as the input picture. Even when, say, multiplying each R,G,B value by 1.2, I am not seeing the grid effect. Therefore, I am fairly confident this is being caused by the colCh function (i.e. the randomness).

Update 2: I have updated my code to incorporate Sascha's suggestions. First, I moved random.seed() outside of the function so that it is not reseeding based on the system time in every iteration. Second, while I am not quite sure I understand how there is bias in my original function, I am now sampling from a positive/negative distribution. Unfortunately, I am still seeing the grid effect. Here is my new code:

random.seed()
def colCh(cVal):
  rnd = random.uniform(-75,75)
  newVal = int(max(min(cVal + rnd,255),0))
  return newVal

Any more ideas?

snoski
  • 174
  • 11
  • 2
    That grid seems to align along with the JPEG blocks. – Dan D. Mar 01 '17 at 02:06
  • Thanks, Dan, for the possible lead. I have updated my question with a clarification regarding the file formats used. I definitely need to research this more to understand if it could be the culprit. – snoski Mar 02 '17 at 05:59

1 Answers1

0

As imgur is down for me right now, some guessing:

Your usage of PRNGs is a bit scary. Don't use time-based seeds in very frequently called loops. It's very much possible, that the same seeds are generated and of course this will generate patterns. (granularity of time + number of random-bits used matter here)

So: seed your PRNG once! Don't do this every time, don't do this for every channel. Seed one global PRNG and use it for all operations.

There should be no pattern then.

(If there is: also check the effect of interpolation = image-size change)

Edit: As imgur is on now, i recognized the macro-block like patterns, like Dan mentioned in the comments. Please change your PRNG-usage first before further analysis. And maybe show more complete code.

It may be possible, that you recompressed the output and JPEG-compression emphasized the effects observed before.

Another thing is:

newVal = max(min(cVal - 75 + rnd,255),0)

There is a bit of a bias here (better approach: sample from symmetric negative/positive distribution and clip between 0,255), which can also emphasize some effect (what looked those macroblocks before?).

sascha
  • 32,238
  • 6
  • 68
  • 110
  • Thanks sascha! This makes good sense. I will try your suggestion of seeding only once, and I will mark this as an answer if it works. I am also interested in the possible role JPEG-compression may have played as you and Dan both alluded. I am quite a novice in every aspect of this project, but I have zero understanding of jpeg compression. I have edited my question to include information about input and output file formats. – snoski Mar 02 '17 at 05:54
  • I edited my code so that it seeded the PRNG only once, and it unfortunately is still resulting in the same grid. So I can't mark this as the answer, but I do appreciate the advice regarding the dangers of seeding in frequent iterations! – snoski Mar 02 '17 at 06:16
  • Then change the bias-stuff too. – sascha Mar 02 '17 at 11:07
  • OK, sascha, I have updated my question to reflect my attempt at sampling from a symmetric negative/positive distribution. By the way, I am not sure exactly how there was bias in my original code. Care to explain? – snoski Mar 11 '17 at 23:59