Studies in Perception I: A Document-Based Chronology, 1966–1969

Short answer

Studies in Perception I is a computer-processed photographic print made at Bell Telephone Laboratories by Leon D. Harmon and Kenneth C. Knowlton. The earliest dated documents I could open give 1967. The Museum of Modern Art listed Studies in Perception I, II, and III with the date 1967 in its press release of 27 November 1968. The Victoria and Albert Museum holds a screenprint dated 1967 and inscribed “© 1967 Knowlton/Harmon”. Two secondary sources, A. Michael Noll’s 2016 history in Leonardo and a 2021 article by Jim Boulton, say 1966, and so does a note in the V&A record of a 1997 laser print (E.963-2008): “Original print produced in 1966”. The same museum dates the screenprint E.35-2020 to 1967. I found no document behind the 1966 year. Noll’s 2022 recollection says 1967.

Reclining nude rendered in small black-and-white symbols, with an enlarged detail at left
Ken Knowlton and Leon Harmon, the reclining figure of Studies in Perception I (Bell Labs, 1967), built from small symbols, with an enlarged detail. (reproduced in Silvers (1996), Fig. 2.10)

What the print is

A photograph was scanned, the average brightness of each small area was computed, and each area was replaced by a small pattern chosen to match that brightness. The MoMA release of 1968 describes it this way: a 35mm transparency scanned by a flying-spot scanner; brightness averaged per fragment; each level drawn as micropatterns inside an 11 × 11 square; a random choice among the patterns that fit the level; output on microfilm, then photographed. The patterns are described in that release with examples such as a cat and an umbrella.

Typewritten page: Leon D. Harmon, Kenneth C. Knowlton, Studies in Perception I, II, and III 1967, computer-processed photographic prints
The entry for Studies in Perception I, II, and III, dated 1967, with the three print sizes and the description of the process: flying-spot scanner, average brightness per fragment, micropatterns in an 11 × 11 square. (The Museum of Modern Art, press release No. 123, 27 November 1968, p. 29, MoMA press archive)

For the history of mosaics, the point is the principle: small marks chosen by measured brightness. It is a precursor of the later algorithms I describe in Photographic Mosaics: How the Algorithms Developed, 1966–2026.

Chronology, with the source for each line

1966196719681969“1966”Noll 2016, Boulton 2021, V&A E.963-2008 note; no document citedV&A screenprint, “© 1967”V&A E.35-2020, object inscriptionReproduced in The New York Times11 Oct 1967; via V&A and Noll, not openedA copy at Cybernetic Serendipity, LondonNoll 2022; month not givenMoMA release No. 123 lists it as 1967press preview 25 Nov 1968The Machine …, MoMA New York27 Nov 1968 – 9 Feb 1969Knowlton’s evening of computer film, MoMArelease of 11 Nov 1968Tour (scheduled): Houston, Rice Museum25 Mar – 18 May 1969Tour: San Francisco Museum of Art23 Jun – 24 Aug 1969
The dates in the chronology on one axis, time running downwards. Filled marks and bars: documents I opened. Half-filled: a document reported by a source I read. Brackets: a year without a day; dashed, a statement with no document behind it. The Houston and San Francisco bars are the exhibition's tour; the documents do not say whether this print travelled with it. For Houston, MoMA's own exhibition page names the Rice Museum, while the 1968 advance sheet names the University of St. Thomas. (diagram drawn from the sources in the table)
Date What the source says Source Kind
1966 “a picture of a reclining nude in 1966” Noll, Leonardo 49(1), 2016 Secondary; no document cited for the year
1966 “Original print produced in 1966” (a note on the 1997 laser print) V&A E.963-2008 Museum catalogue note; no document cited
1967 Original printout 12 feet wide, undated by the V&A; press conference at Robert Rauschenberg’s loft; reproduced in The New York Times, 11 October 1967 V&A record E.35-2020; Noll cites Lieberman, NYT, 11 Oct 1967, p. 49 Museum catalogue; the newspaper itself I have not opened
1967 V&A screenprint dated 1967, inscribed “© 1967 Knowlton/Harmon” V&A E.35-2020 Object inscription
27 Nov 1968 – 9 Feb 1969 The Machine as Seen at the End of the Mechanical Age, MoMA, about 220 works, press preview 25 Nov 1968 MoMA advance information No. 108A Primary
27 Nov 1968 Studies in Perception I, II, and III 1967; prints of 2½′ × 5′, 2′ × 3′, 2′ × 3′; credited to Harmon and Knowlton, Computer Program Research, Bell Telephone Laboratories MoMA press release, 27 Nov 1968, p. 29 Primary
2 Dec 1968 Knowlton presents “An Evening of Computer-Produced Film” at MoMA MoMA release of 11 Nov 1968, bound in the same PDF, p. 15 Primary
Museum of Modern Art letterhead, No. 123, for release Wednesday, November 27, 1968
The head of the same release: for release Wednesday, 27 November 1968; press preview Monday, 25 November 1968. (The Museum of Modern Art, press release No. 123, p. 1, MoMA press archive)
Typewritten advance information sheet listing the showings in New York, Houston and San Francisco
The exhibition's dates and its tour: New York, 27 November 1968 to 9 February 1969, then Houston and San Francisco in 1969. (The Museum of Modern Art, Advance Information No. 108A, MoMA press archive)

Sizes

Three sizes appear and they refer to different objects. The original printout was about 12 feet wide (V&A; Noll; Boulton). The print listed by MoMA in 1968 is 2½′ × 5′, which is 30 × 60 inches. A V&A record notes a later laser print (E.963-2008); the 1997 date and 32.3 × 55.6 cm with mount come from that object’s own page, which I read in an earlier pass. A copy was also shown at Cybernetic Serendipity, London, 1968 (Noll 2022).

Original printoutabout 12 feet wide (V&A, Noll, Boulton); height not statedMoMA print, 19682½′ × 5′ (30 × 60 in)V&A laser print, 199732.3 × 55.6 cm, with mount1 foot
The three recorded sizes on one scale. They are different objects, not three measurements of one print. Proportions are drawn as width by height, landscape, as the reclining figure suggests; the documents give the numbers, not the orientation. (diagram drawn from V&A E.35-2020, E.963-2008 and the MoMA release)

What I could not establish

  • The date of the Rauschenberg press conference. The newspaper date is 11 October 1967; the event date is unknown to me.
  • Whether Studies in Perception I was one of the nine works selected from the E.A.T. competition. The MoMA documents I read do not say.
  • The 1968 catalogue entry (Hultén, p. 207). I only know it through Noll’s quotation.
  • Knowlton’s “Portrait of the Artist as a Young Scientist” (YLEM Journal, 2005). I found no copy.
  • The story that the credit of “artist” and “engineer” was decided by a coin toss. It appears in Noll (2016, attributing it to Knowlton). It is not in Knowlton’s 2001 essay.
  • The year in the 1968 catalogue. As Noll (2022) quotes it, the entry reads “Studies in Perception, I 1968 … 30 x 60 [inches]”, while the MoMA press release of the same exhibition says 1967. I have not seen the catalogue.
  • Any claim that this was the first computer-made nude. Knowlton (2001) reports that Billy Klüver says a collaboration resulted in a nude being published in The New York Times for the first time. That is a report of a statement, and I found no primary source for “first”.

Credits

Harmon is credited as artist and Knowlton as engineer in the catalogue, according to Noll. Knowlton wrote in 2001 that at Bell Labs he collaborated with five artists, including Harmon, and saw himself as the engineer of each pair. Who took the photograph is disputed: Noll (2016) says Harmon; the V&A record says Max Mathews photographed the dancer and choreographer Deborah Hay; Noll (2022) reports that Mathews himself said in 1998 that Harmon took it, and that Hay told a web historian it was Mathews. I did not find a document that settles it.

Ken Knowlton, grey-haired, in a patterned short-sleeved shirt, standing against a stone wall
Ken Knowlton in 2007. (photograph by Golan Levin, Wikimedia Commons, CC0)

A reconstruction of the method

The program that made the print has not, as far as I know, been published. The Museum of Modern Art release of 1968 describes it closely enough to rebuild the method, so I did, in about three hundred lines of Python. It follows the stages of the release that concern the picture; the scanning to magnetic tape and the microfilm output are not reconstructed. The picture is divided into rows and fragments per row. The average brightness of each fragment is computed and reduced to one of twelve levels. Each level is drawn as a micropattern in an 11 × 11 square, with as many black dots as the brightness calls for. And for each fragment the program chooses at random among the patterns that fit its level.

Some choices are mine, because the release does not make them: the fifteen signs and their variants, the number of levels, the grid of 160 × 114 fragments and the source picture, Jacques-Louis David’s Madame Récamier (1800), a public-domain painting of a reclining figure. The original symbols, the photograph and the program belong to Harmon and Knowlton, and none of them is reproduced in this section. What the exercise shows is how little the method needs: no search, no comparison of shapes, only a count of black dots and a roll of the dice.

Grid of small black-and-white pictograms in twelve rows, from almost white to almost black
The micropatterns of the reconstruction, one row per brightness level, lightest at the top. Fifteen signs, each as a line, a thick line and a solid shape, and each reversed out of black; within a row the program chooses at random. These are my signs, not Knowlton and Harmon’s. (reconstruction, knowlton_harmon.py)
A reclining woman in a white dress on a daybed, rendered entirely in tiny black-and-white pictograms
The method applied to a public-domain painting of a reclining figure: 160 × 114 fragments, twelve levels, one 11 × 11 micropattern per fragment. (reconstruction, knowlton_harmon.py, seed 1967; source image Jacques-Louis David, Madame Récamier, 1800, Louvre, public domain)
Enlarged detail showing individual pictograms: keys, umbrellas, moons, hearts, houses, crosses
Detail around the head, enlarged four times: up close the picture is a field of cats, keys, umbrellas, moons and notes; from a distance it is tone. (reconstruction, knowlton_harmon.py)
Python source: knowlton_harmon.py (337 lines, standard library and Pillow)
"""A reconstruction of the method of Harmon and Knowlton's Studies in Perception I (1967),
written from the description in the Museum of Modern Art press release of 27 November 1968, p. 29:

  1. the picture is fragmented into rows and fragments per row;
  2. the average brightness of each fragment is computed and encoded as a number;
  3. a brightness is reproduced by the number of black dots in an 11 x 11 square,
     the dots organised into micropatterns (e.g. a cat, an umbrella);
  4. for each fragment the computer makes a random choice among the patterns that fit its level.

This is not the original program, which as far as I know is not published, and these are not the original symbols.
Our choices: the pictograms below, the number of levels (LEVELS), the grid size and the contrast stretch.

Usage: python3 knowlton_harmon.py SOURCE_IMAGE OUT_DIR [--cols 96] [--seed 1967] [--crop L T R B]
"""
import argparse
import random
from pathlib import Path

from PIL import Image, ImageOps

CELL = 11      # side of a micropattern, as in the MoMA description
LEVELS = 12    # brightness levels; our choice, the release does not give the number

# 11 x 11 pictograms, '#' = black. Drawn for this reconstruction.
GLYPHS = {
    "cat": """
...#...#...
...##.##...
...#####...
..#.#.#.#..
..#######..
...#####...
....###....
...#####...
..#######..
..#######..
...##.##...""",
    "umbrella": """
.....#.....
...#####...
..#######..
.#########.
###########
#.#.#.#.#.#
.....#.....
.....#.....
.....#.....
.....#.#...
......#....""",
    "house": """
.....#.....
....###....
...#####...
..#######..
.#########.
..#######..
..##...##..
..##.#.##..
..##...##..
..#######..
..#######..""",
    "tree": """
.....#.....
....###....
...#####...
..#######..
....###....
...#####...
..#######..
.#########.
.....#.....
.....#.....
....###....""",
    "star": """
.....#.....
.....#.....
....###....
###########
.#########.
..#######..
...#####...
..###.###..
..##...##..
.##.....##.
.#.......#.""",
    "heart": """
...........
.###...###.
###########
###########
###########
.#########.
..#######..
...#####...
....###....
.....#.....
...........""",
    "fish": """
...........
...#####...
.#######..#
#########.#
###.######.
###########
#########.#
.#######..#
...#####...
...........
...........""",
    "key": """
..###......
.#...#.....
.#...#.....
.#...#.....
..###......
...#.......
...#.......
...###.....
...#.......
...###.....
...........""",
    "cup": """
...........
...........
.#######...
.#######.#.
.#######..#
.#######..#
.#######.#.
..#####....
...###.....
#########..
...........""",
    "bell": """
.....#.....
....###....
...#####...
...#####...
..#######..
..#######..
..#######..
.#########.
###########
.....#.....
...........""",
    "moon": """
...####....
..###......
.###.......
.##........
###........
###........
###........
.##........
.###.......
..###......
...####....""",
    "bird": """
...........
...........
#.........#
.#.......#.
..#.....#..
...#...#...
....#.#....
.....#.....
...........
...........
...........""",
    "cross": """
...........
...........
.....#.....
.....#.....
.....#.....
..#######..
.....#.....
.....#.....
.....#.....
...........
...........""",
    "note": """
...........
......##...
......#.#..
......#..#.
......#....
......#....
......#....
....###....
...####....
...###.....
...........""",
    "arrow": """
.....#.....
....###....
...#####...
..#######..
.....#.....
.....#.....
.....#.....
.....#.....
.....#.....
.....#.....
.....#.....""",
}


def parse(art: str) -> tuple[tuple[int, ...], ...]:
    rows = [r for r in art.strip("\n").split("\n")]
    if len(rows) != CELL or any(len(r) != CELL for r in rows):
        raise ValueError(f"pictogram must be {CELL} x {CELL}")
    return tuple(tuple(1 if c == "#" else 0 for c in r) for r in rows)


def outline(p: tuple) -> tuple:
    """Keep the black pixels that touch a white pixel or the border: a lighter version of the same sign."""
    def edge(y: int, x: int) -> bool:
        return any(not (0 <= y + dy < CELL and 0 <= x + dx < CELL) or not p[y + dy][x + dx]
                   for dy, dx in ((-1, 0), (1, 0), (0, -1), (0, 1)))
    return tuple(tuple(1 if p[y][x] and edge(y, x) else 0 for x in range(CELL)) for y in range(CELL))


def thick_outline(p: tuple) -> tuple:
    """Two-pixel outline: between the line and the solid sign in darkness."""
    inner = outline(tuple(tuple(v and not o for v, o in zip(r, ro)) for r, ro in zip(p, outline(p))))
    line = outline(p)
    return tuple(tuple(1 if a or b else 0 for a, b in zip(r1, r2)) for r1, r2 in zip(line, inner))


def invert(p: tuple) -> tuple:
    return tuple(tuple(1 - v for v in row) for row in p)


def darkness(p: tuple) -> int:
    return sum(map(sum, p))


def variants() -> list[tuple[str, tuple]]:
    """Each sign as line, thick line and solid, and the three reversed out of black: six darknesses per sign."""
    out = []
    for name, art in GLYPHS.items():
        solid = parse(art)
        for kind, p in (("line", outline(solid)), ("thick", thick_outline(solid)), ("solid", solid)):
            out += [(f"{name}/{kind}", p), (f"{name}/{kind}-reversed", invert(p))]
    blank = tuple((0,) * CELL for _ in range(CELL))
    out += [("blank", blank), ("full", invert(blank))]
    unique: dict[tuple, str] = {}
    for n, q in out:  # thin signs give the same pattern as line and as solid; keep one
        unique.setdefault(q, n)
    return [(n, q) for q, n in unique.items()]


def level_of(black: float) -> int:
    return min(LEVELS - 1, int(black * LEVELS))


def pattern_table() -> dict[int, list[tuple[str, tuple]]]:
    """Patterns grouped by the brightness level their count of black dots fits."""
    table: dict[int, list] = {k: [] for k in range(LEVELS)}
    for name, p in variants():
        table[level_of(darkness(p) / CELL ** 2)].append((name, p))
    empty = [k for k, v in table.items() if not v]
    if empty:
        raise ValueError(f"no pattern fits levels {empty}; add pictograms or change LEVELS")
    return table


def fragment_levels(src: Image.Image, cols: int) -> list[list[int]]:
    """Steps 1 and 2: rows and fragments per row, average brightness of each, encoded as a level."""
    grey = ImageOps.autocontrast(src.convert("L"), cutoff=1)
    rows = round(cols * grey.height / grey.width)
    small = grey.resize((cols, rows), Image.Resampling.BOX)  # BOX = the mean of each fragment
    values = small.tobytes()  # mode L: one byte per fragment
    return [[level_of(1 - values[y * cols + x] / 255) for x in range(cols)] for y in range(rows)]


def render(levels: list[list[int]], table: dict, seed: int) -> tuple[Image.Image, list[list[str]]]:
    """Steps 3 and 4: draw an 11 x 11 micropattern per fragment, chosen at random among those that fit."""
    rng = random.Random(seed)
    rows, cols = len(levels), len(levels[0])
    img = Image.new("1", (cols * CELL, rows * CELL), 1)
    px = img.load()
    assert px is not None
    chosen = []
    for gy, row in enumerate(levels):
        names = []
        for gx, lv in enumerate(row):
            name, p = rng.choice(table[lv])
            names.append(name)
            for y in range(CELL):
                for x in range(CELL):
                    if p[y][x]:
                        px[gx * CELL + x, gy * CELL + y] = 0
        chosen.append(names)
    return img, chosen


def chart(table: dict, scale: int = 6) -> Image.Image:
    """The pattern set, one row per level, lightest at the top."""
    gap, width = 3, max(len(v) for v in table.values())
    side = CELL * scale
    img = Image.new("L", (width * (side + gap * scale) + gap * scale, LEVELS * (side + gap * scale) + gap * scale), 255)
    for lv in range(LEVELS):
        for i, (_, p) in enumerate(sorted(table[lv], key=lambda t: darkness(t[1]))):
            tile = Image.new("L", (CELL, CELL), 255)
            tile.putdata([0 if v else 255 for row in p for v in row])
            tile = ImageOps.expand(tile.resize((side, side), Image.Resampling.NEAREST), border=1, fill=180)
            img.paste(tile, (gap * scale + i * (side + gap * scale), gap * scale + lv * (side + gap * scale)))
    return img


def main() -> None:
    ap = argparse.ArgumentParser(description=__doc__.split("\n")[0])
    ap.add_argument("source")
    ap.add_argument("out_dir")
    ap.add_argument("--cols", type=int, default=96)
    ap.add_argument("--seed", type=int, default=1967)
    ap.add_argument("--crop", type=float, nargs=4, metavar=("L", "T", "R", "B"), default=(0, 0, 1, 1),
                    help="region of the source to use, as fractions of its width and height")
    a = ap.parse_args()
    out = Path(a.out_dir)
    out.mkdir(parents=True, exist_ok=True)
    table = pattern_table()
    full = Image.open(a.source)
    l, t, r, b = a.crop
    src = full.crop((round(l * full.width), round(t * full.height), round(r * full.width), round(b * full.height)))
    levels = fragment_levels(src, a.cols)
    img, _ = render(levels, table, a.seed)
    img.save(out / "reconstruction.png")
    chart(table).save(out / "pattern-chart.png")
    counts = {lv: len(v) for lv, v in table.items()}
    print(f"{len(levels[0])} x {len(levels)} fragments, image {img.size[0]} x {img.size[1]} px; patterns per level {counts}")


if __name__ == "__main__":
    main()
The complete program. Run it as python3 knowlton_harmon.py SOURCE OUT_DIR --cols 160 --crop 0.12 0.12 0.92 0.92 to reproduce the figures above. (reconstruction of the method; free to reuse)

Sources

  1. The Museum of Modern Art, press release, 27 November 1968 (The Machine as Seen at the End of the Mechanical Age): https://www.moma.org/docs/press_archives/4149/releases/MOMA_1968_July-December_0081.pdf
  2. The Museum of Modern Art, “Advance Information”, No. 108A: https://www.moma.org/docs/press_archives/4134/releases/MOMA_1968_July-December_0066_108a.pdf
  3. Victoria and Albert Museum, E.35-2020: https://collections.vam.ac.uk/item/O1488651/
  4. A. Michael Noll, “Early Digital Computer Art at Bell Telephone Laboratories, Incorporated”, Leonardo 49(1), 2016, pp. 55–65 (author’s copy: https://ethw.org/First-Hand:Early_Digital_Art_At_Bell_Telephone_Laboratories,_Inc)
  5. A. Michael Noll, “Harmon-Knowlton’s ‘The Nude’ Overshadows All”, ETHW, 28 August 2022: https://ethw.org/First-Hand:Harmon-Knowlton%27s_%22The_Nude%22_Overshadows_All
  6. Kenneth C. Knowlton, “On the Frustrations of Collaborating with Artists”, Computer Graphics 35(3), August 2001, pp. 20–22: https://kenknowlton.com/pages/05collab.htm
  7. Jim Boulton, “Studies in Perception — a Digital Restoration Story”, Medium, 14 March 2021: https://jimboulton.medium.com/studies-in-perception-a-restoration-story-241cd8c75ab1

Version and how to cite

Version 1.1, 24 October 2026. An archival PDF (version 1.0, without third-party figures) is deposited at Zenodo: doi:10.5281/zenodo.23609541.

Cite as: Tsevis, Charis (ORCID: 0009-0009-0378-676X). "Studies in Perception I: A Document-Based Chronology, 1966–1969." Tsevis Studio, version 1.1, 24 October 2026. https://www.tsevis.com/blog/studies-in-perception-i-chronology. Archival copy: https://doi.org/10.5281/zenodo.23609541

Changelog

  • v0.2 (2026-10-10): independent check applied: photographer conflict, catalogue year 1968 as quoted by Noll, release date of p. 15.
  • v1.1 (2026-10-24): added the Zenodo DOI for the archival copy (10.5281/zenodo.23609541) to this box.
  • v1.0 (2026-10-24): first publication, after a second independent check of the figures, captions, tour dates and the reconstruction (Houston venue named as in MoMA’s own exhibition page; the 1966 note on V&A E.963-2008 added).
  • v0.2 (draft, 2026-10-10): first text, from MoMA 1968 releases, V&A E.35-2020, Noll 2016 and 2022, Knowlton 2001, Boulton 2021.

Corrections

None yet. Corrections will be listed here with date and reason. Related: my history article was corrected from 1966 to 1967 in its version 1.2 (10 October 2026), on the documents above.

Images: the 1968 MoMA press-release pages are reproduced as documents, credited and linked to their source; the print itself appears once, as reproduced in Rob Silvers’s 1996 thesis, as a quotation for discussion, with credit; the photograph of Ken Knowlton (2007) is by Golan Levin, CC0; Madame Récamier is in the public domain. The figures drawn for this article and the reconstruction are mine.

To report an error, write to me through the contact page.

Next
Next

Annotated Bibliography of Artistic Image Mosaics, 1967–2026