10

I'm using OpenCV to read images into numpy.array, and they have the following shape.

import cv2

def readImages(path):
    imgs = []
    for file in os.listdir(path):
        if file.endswith('.png'):
            img = cv2.imread(file)
            imgs.append(img)
    imgs = numpy.array(imgs)
    return (imgs)

imgs = readImages(...)
print imgs.shape  # (100, 718, 686, 3)

Each of the image has 718x686 pixels/dimension. There are 100 images.

I don't want to work on 718x686, I'd like to combine the pixels into a single dimension. That is, the shape should look like: (100,492548,3). Is there anyway either in OpenCV (or any other library) or Numpy that allows me to do that?

1
  • I don't understand where you get the end shape from. But have you tried reshaping before putting them all into one array? If if have a (718, 686) array called X you can flatten it into eg a row vector like this X.reshape((1, -1)). Commented Apr 2, 2016 at 8:34

4 Answers 4

13

Without modifying your reading function:

imgs = readImages(...)
print imgs.shape  # (100, 718, 686, 3)

# flatten axes -2 and -3, using -1 to autocalculate the size
pixel_lists = imgs.reshape(imgs.shape[:-3] + (-1, 3))
print pixel_lists.shape  # (100, 492548, 3)
Sign up to request clarification or add additional context in comments.

1 Comment

Minor suggestion: pixel_lists = imgs.reshape(imgs.shape[:-3] + (-1, imgs.shape[3]))
6

In case anyone wants it. Here's a general way of doing this

import functools
def combine_dims(a, i=0, n=1):
  """
  Combines dimensions of numpy array `a`, 
  starting at index `i`,
  and combining `n` dimensions
  """
  s = list(a.shape)
  combined = functools.reduce(lambda x,y: x*y, s[i:i+n+1])
  return np.reshape(a, s[:i] + [combined] + s[i+n+1:])

With this function you could use it like this:

imgs = combine_dims(imgs, 1) # combines dimension 1 and 2
# imgs.shape = (100, 718*686, 3)

2 Comments

please test if speed is the same as raw reshape -- I'm not sure that it is
This function uses np.reshape, so it cannot be the same speed as np.reshape. Using %timeit in iPython, this solution nearly doubles the cost of using np.reshape with a fixed input. However, double of almost nothing, is still almost nothing; each taking approximately 0.9 microseconds to complete each execution. (Reshaping is O(1). i.e. not dependent on array size). Why? Is this an issue?
5
def combine_dims(a, start=0, count=2):
    """ Reshapes numpy array a by combining count dimensions, 
        starting at dimension index start """
    s = a.shape
    return numpy.reshape(a, s[:start] + (-1,) + s[start+count:])

This function does what you need in a more general way.

imgs = combine_dims(imgs, 1) # combines dimension 1 and 2
# imgs.shape == (100, 718*686, 3)

It works by using numpy.reshape, which turns an array of one shape into an array with the same data but viewed as another shape. The target shape is just the initial shape, but with the dimensions to be combined replaced by -1. numpy uses -1 as a flag to indicate that it should work out itself how big that dimension should be (based on the total number of elements.)

This code is essentially a simplified version of Multihunter's answer, but my edit was rejected and hinted that it should be a separate answer. So there you go.

1 Comment

This is a much better solution. Dunno how I forgot about using -1... Anyway; which would you prefer? I add "check out @Andrew Kay 's answer for a neater solution" to my answer, or just edit my answer myself to use this version.
2
import cv2
import os
import numpy as np

def readImages(path):
    imgs = np.empty((0, 492548, 3))
    for file in os.listdir(path):
        if file.endswith('.png'):
            img = cv2.imread(file)
            img = img.reshape((1, 492548, 3))
            imgs = np.append(imgs, img, axis=0)
    return (imgs)

imgs = readImages(...)
print imgs.shape  # (100, 492548, 3)

The trick was to reshape and append to a numpy array. It's not good practice to hardcode the length of the vector (492548) so if I were you I'd also add a line that calculates this number and puts it in a variable, for use in the rest of the script.

1 Comment

Using -1 will make numpy calculate 492548 for you

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.